A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lte-spectrum-phy.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009, 2011 CTTC
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Nicola Baldo <nbaldo@cttc.es>
7 * Giuseppe Piro <g.piro@poliba.it>
8 * Marco Miozzo <marco.miozzo@cttc.es> (add physical error model)
9 */
10
11#include "lte-spectrum-phy.h"
12
13#include "lte-chunk-processor.h"
15#include "lte-mi-error-model.h"
18
19#include <ns3/antenna-model.h>
20#include <ns3/boolean.h>
21#include <ns3/config.h>
22#include <ns3/double.h>
23#include <ns3/log.h>
24#include <ns3/object-factory.h>
25#include <ns3/simulator.h>
26#include <ns3/trace-source-accessor.h>
27
28#include <cmath>
29
30namespace ns3
31{
32
33NS_LOG_COMPONENT_DEFINE("LteSpectrumPhy");
34
35/// duration of SRS portion of UL subframe
36/// = 1 symbol for SRS -1ns as margin to avoid overlapping simulator events
37static const Time UL_SRS_DURATION = NanoSeconds(71429 - 1);
38
39/// duration of the control portion of a subframe
40/// = 0.001 / 14 * 3 (ctrl fixed to 3 symbols) -1ns as margin to avoid overlapping simulator events
41static const Time DL_CTRL_DURATION = NanoSeconds(214286 - 1);
42
43/// Effective coding rate
44static const double EffectiveCodingRate[29] = {
45 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,
46 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,
47};
48
52
53TbId_t::TbId_t(const uint16_t a, const uint8_t b)
54 : m_rnti(a),
55 m_layer(b)
56{
57}
58
59/**
60 * Equality operator
61 *
62 * @param a lhs
63 * @param b rhs
64 * @returns true if rnti and layer are equal
65 */
66bool
67operator==(const TbId_t& a, const TbId_t& b)
68{
69 return ((a.m_rnti == b.m_rnti) && (a.m_layer == b.m_layer));
70}
71
72/**
73 * Less than operator
74 *
75 * @param a lhs
76 * @param b rhs
77 * @returns true if rnti less than ro rnti equal and layer less than
78 */
79bool
80operator<(const TbId_t& a, const TbId_t& b)
81{
82 return ((a.m_rnti < b.m_rnti) || ((a.m_rnti == b.m_rnti) && (a.m_layer < b.m_layer)));
83}
84
86
88 : m_state(IDLE),
89 m_cellId(0),
90 m_componentCarrierId(0),
91 m_transmissionMode(0),
92 m_layersNum(1)
93{
94 NS_LOG_FUNCTION(this);
96 m_random->SetAttribute("Min", DoubleValue(0.0));
97 m_random->SetAttribute("Max", DoubleValue(1.0));
100
101 for (uint8_t i = 0; i < 7; i++)
102 {
103 m_txModeGain.push_back(1.0);
104 }
105}
106
108{
109 NS_LOG_FUNCTION(this);
110 m_expectedTbs.clear();
111 m_txModeGain.clear();
112}
113
114void
134
135/**
136 * Output stream output operator
137 *
138 * @param os output stream
139 * @param s state
140 * @returns output stream
141 */
142std::ostream&
143operator<<(std::ostream& os, LteSpectrumPhy::State s)
144{
145 switch (s)
146 {
148 os << "IDLE";
149 break;
151 os << "RX_DATA";
152 break;
154 os << "RX_DL_CTRL";
155 break;
157 os << "TX_DATA";
158 break;
160 os << "TX_DL_CTRL";
161 break;
163 os << "TX_UL_SRS";
164 break;
165 default:
166 os << "UNKNOWN";
167 break;
168 }
169 return os;
170}
171
172TypeId
174{
175 static TypeId tid =
176 TypeId("ns3::LteSpectrumPhy")
178 .SetGroupName("Lte")
179 .AddTraceSource("TxStart",
180 "Trace fired when a new transmission is started",
182 "ns3::PacketBurst::TracedCallback")
183 .AddTraceSource("TxEnd",
184 "Trace fired when a previously started transmission is finished",
186 "ns3::PacketBurst::TracedCallback")
187 .AddTraceSource("RxStart",
188 "Trace fired when the start of a signal is detected",
190 "ns3::PacketBurst::TracedCallback")
191 .AddTraceSource("RxEndOk",
192 "Trace fired when a previously started RX terminates successfully",
194 "ns3::Packet::TracedCallback")
195 .AddTraceSource("RxEndError",
196 "Trace fired when a previously started RX terminates with an error",
198 "ns3::Packet::TracedCallback")
199 .AddAttribute("DataErrorModelEnabled",
200 "Activate/Deactivate the error model of data (TBs of PDSCH and PUSCH) "
201 "[by default is active].",
202 BooleanValue(true),
205 .AddAttribute("CtrlErrorModelEnabled",
206 "Activate/Deactivate the error model of control (PCFICH-PDCCH "
207 "decodification) [by default is active].",
208 BooleanValue(true),
211 .AddTraceSource("DlPhyReception",
212 "DL reception PHY layer statistics.",
214 "ns3::PhyReceptionStatParameters::TracedCallback")
215 .AddTraceSource("UlPhyReception",
216 "DL reception PHY layer statistics.",
218 "ns3::PhyReceptionStatParameters::TracedCallback");
219 return tid;
220}
221
224{
225 NS_LOG_FUNCTION(this);
226 return m_device;
227}
228
231{
232 NS_LOG_FUNCTION(this);
233 return m_mobility;
234}
235
236void
242
243void
249
250void
256
259{
260 return m_channel;
261}
262
268
269void
271{
272 NS_LOG_FUNCTION(this << txPsd);
273 NS_ASSERT(txPsd);
274 m_txPsd = txPsd;
275}
276
277void
279{
280 NS_LOG_FUNCTION(this << noisePsd);
281 NS_ASSERT(noisePsd);
282 m_rxSpectrumModel = noisePsd->GetSpectrumModel();
283 m_interferenceData->SetNoisePowerSpectralDensity(noisePsd);
284 m_interferenceCtrl->SetNoisePowerSpectralDensity(noisePsd);
285}
286
287void
289{
290 NS_LOG_FUNCTION(this);
291 m_cellId = 0;
292 m_state = IDLE;
294 m_layersNum = 1;
300 m_expectedTbs.clear();
302 m_rxPacketBurstList.clear();
303 m_txPacketBurst = nullptr;
304 m_rxSpectrumModel = nullptr;
305
306 // Detach from the channel, because receiving any signal without
307 // spectrum model is an error.
308 if (m_channel)
309 {
310 m_channel->RemoveRx(this);
311 }
312}
313
314void
320
321void
327
328void
334
335void
341
342void
348
349void
355
356void
362
365{
366 return m_antenna;
367}
368
369void
375
376void
378{
379 ChangeState(newState);
380}
381
382void
384{
385 NS_LOG_LOGIC(this << " state: " << m_state << " -> " << newState);
386 m_state = newState;
387}
388
389void
394
395bool
397 std::list<Ptr<LteControlMessage>> ctrlMsgList,
398 Time duration)
399{
400 NS_LOG_FUNCTION(this << pb);
401 NS_LOG_LOGIC(this << " state: " << m_state);
402
404
405 switch (m_state)
406 {
407 case RX_DATA:
408 case RX_DL_CTRL:
409 case RX_UL_SRS:
410 NS_FATAL_ERROR("cannot TX while RX: according to FDD channel access, the physical layer "
411 "for transmission cannot be used for reception");
412 break;
413
414 case TX_DATA:
415 case TX_DL_CTRL:
416 case TX_UL_SRS:
417 NS_FATAL_ERROR("cannot TX while already TX: the MAC should avoid this");
418 break;
419
420 case IDLE: {
421 /*
422 m_txPsd must be set by the device, according to
423 (i) the available subchannel for transmission
424 (ii) the power transmission
425 */
427 m_txPacketBurst = pb;
428
429 // we need to convey some PHY meta information to the receiver
430 // to be used for simulation purposes (e.g., the CellId). This
431 // is done by setting the ctrlMsgList parameter of
432 // LteSpectrumSignalParametersDataFrame
437 txParams->duration = duration;
438 txParams->txPhy = GetObject<SpectrumPhy>();
439 txParams->txAntenna = m_antenna;
440 txParams->psd = m_txPsd;
441 txParams->packetBurst = pb;
442 txParams->ctrlMsgList = ctrlMsgList;
443 txParams->cellId = m_cellId;
444 m_channel->StartTx(txParams);
446 }
447 return false;
448
449 default:
450 NS_FATAL_ERROR("unknown state");
451 return true;
452 }
453}
454
455bool
457{
458 NS_LOG_FUNCTION(this << " PSS " << (uint16_t)pss);
459 NS_LOG_LOGIC(this << " state: " << m_state);
460
461 switch (m_state)
462 {
463 case RX_DATA:
464 case RX_DL_CTRL:
465 case RX_UL_SRS:
466 NS_FATAL_ERROR("cannot TX while RX: according to FDD channel access, the physical layer "
467 "for transmission cannot be used for reception");
468 break;
469
470 case TX_DATA:
471 case TX_DL_CTRL:
472 case TX_UL_SRS:
473 NS_FATAL_ERROR("cannot TX while already TX: the MAC should avoid this");
474 break;
475
476 case IDLE: {
477 /*
478 m_txPsd must be set by the device, according to
479 (i) the available subchannel for transmission
480 (ii) the power transmission
481 */
483
484 // we need to convey some PHY meta information to the receiver
485 // to be used for simulation purposes (e.g., the CellId). This
486 // is done by setting the cellId parameter of
487 // LteSpectrumSignalParametersDlCtrlFrame
490
493 txParams->duration = DL_CTRL_DURATION;
494 txParams->txPhy = GetObject<SpectrumPhy>();
495 txParams->txAntenna = m_antenna;
496 txParams->psd = m_txPsd;
497 txParams->cellId = m_cellId;
498 txParams->pss = pss;
499 txParams->ctrlMsgList = ctrlMsgList;
500 m_channel->StartTx(txParams);
502 }
503 return false;
504
505 default:
506 NS_FATAL_ERROR("unknown state");
507 return true;
508 }
509}
510
511bool
513{
514 NS_LOG_FUNCTION(this);
515 NS_LOG_LOGIC(this << " state: " << m_state);
516
517 switch (m_state)
518 {
519 case RX_DATA:
520 case RX_DL_CTRL:
521 case RX_UL_SRS:
522 NS_FATAL_ERROR("cannot TX while RX: according to FDD channel access, the physical layer "
523 "for transmission cannot be used for reception");
524 break;
525
526 case TX_DL_CTRL:
527 case TX_DATA:
528 case TX_UL_SRS:
529 NS_FATAL_ERROR("cannot TX while already TX: the MAC should avoid this");
530 break;
531
532 case IDLE: {
533 /*
534 m_txPsd must be set by the device, according to
535 (i) the available subchannel for transmission
536 (ii) the power transmission
537 */
539 NS_LOG_LOGIC(this << " m_txPsd: " << *m_txPsd);
540
541 // we need to convey some PHY meta information to the receiver
542 // to be used for simulation purposes (e.g., the CellId). This
543 // is done by setting the cellId parameter of
544 // LteSpectrumSignalParametersDlCtrlFrame
549 txParams->duration = UL_SRS_DURATION;
550 txParams->txPhy = GetObject<SpectrumPhy>();
551 txParams->txAntenna = m_antenna;
552 txParams->psd = m_txPsd;
553 txParams->cellId = m_cellId;
554 m_channel->StartTx(txParams);
556 }
557 return false;
558
559 default:
560 NS_FATAL_ERROR("unknown state");
561 return true;
562 }
563}
564
565void
567{
568 NS_LOG_FUNCTION(this);
569 NS_LOG_LOGIC(this << " state: " << m_state);
570
573 m_txPacketBurst = nullptr;
575}
576
577void
579{
580 NS_LOG_FUNCTION(this);
581 NS_LOG_LOGIC(this << " state: " << m_state);
582
586}
587
588void
590{
591 NS_LOG_FUNCTION(this);
592 NS_LOG_LOGIC(this << " state: " << m_state);
593
597}
598
599void
601{
602 NS_LOG_FUNCTION(this << spectrumRxParams);
603 NS_LOG_LOGIC(this << " state: " << m_state);
604
605 Ptr<const SpectrumValue> rxPsd = spectrumRxParams->psd;
606 Time duration = spectrumRxParams->duration;
607
608 // the device might start RX only if the signal is of a type
609 // understood by this device - in this case, an LTE signal.
616 if (lteDataRxParams)
617 {
618 m_interferenceData->AddSignal(rxPsd, duration);
619 StartRxData(lteDataRxParams);
620 }
621 else if (lteDlCtrlRxParams)
622 {
623 m_interferenceCtrl->AddSignal(rxPsd, duration);
624 StartRxDlCtrl(lteDlCtrlRxParams);
625 }
626 else if (lteUlSrsRxParams)
627 {
628 m_interferenceCtrl->AddSignal(rxPsd, duration);
629 StartRxUlSrs(lteUlSrsRxParams);
630 }
631 else
632 {
633 // other type of signal (could be 3G, GSM, whatever) -> interference
634 m_interferenceData->AddSignal(rxPsd, duration);
635 m_interferenceCtrl->AddSignal(rxPsd, duration);
636 }
637}
638
639void
641{
642 NS_LOG_FUNCTION(this);
643 switch (m_state)
644 {
645 case TX_DATA:
646 case TX_DL_CTRL:
647 case TX_UL_SRS:
648 NS_FATAL_ERROR("cannot RX while TX: according to FDD channel access, the physical layer "
649 "for transmission cannot be used for reception");
650 break;
651 case RX_DL_CTRL:
652 NS_FATAL_ERROR("cannot RX Data while receiving control");
653 break;
654 case IDLE:
655 case RX_DATA:
656 // the behavior is similar when
657 // we're IDLE or RX because we can receive more signals
658 // simultaneously (e.g., at the eNB).
659 {
660 // To check if we're synchronized to this signal, we check
661 // for the CellId which is reported in the
662 // LteSpectrumSignalParametersDataFrame
663 if (params->cellId == m_cellId)
664 {
665 NS_LOG_LOGIC(this << " synchronized with this signal (cellId=" << params->cellId
666 << ")");
667 if ((m_rxPacketBurstList.empty()) && (m_rxControlMessageList.empty()))
668 {
670 // first transmission, i.e., we're IDLE and we
671 // start RX
673 m_firstRxDuration = params->duration;
674 NS_LOG_LOGIC(this << " scheduling EndRx with delay "
675 << params->duration.As(Time::S));
677 Simulator::Schedule(params->duration, &LteSpectrumPhy::EndRxData, this);
678 }
679 else
680 {
682 // sanity check: if there are multiple RX events, they
683 // should occur at the same time and have the same
684 // duration, otherwise the interference calculation
685 // won't be correct
687 (m_firstRxDuration == params->duration));
688 }
689
691 if (params->packetBurst)
692 {
693 m_rxPacketBurstList.push_back(params->packetBurst);
694 m_interferenceData->StartRx(params->psd);
695
696 m_phyRxStartTrace(params->packetBurst);
697 }
698 NS_LOG_DEBUG(this << " insert msgs " << params->ctrlMsgList.size());
700 params->ctrlMsgList.begin(),
701 params->ctrlMsgList.end());
702
703 NS_LOG_LOGIC(this << " numSimultaneousRxEvents = " << m_rxPacketBurstList.size());
704 }
705 else
706 {
707 NS_LOG_LOGIC(this << " not in sync with this signal (cellId=" << params->cellId
708 << ", m_cellId=" << m_cellId << ")");
709 }
710 }
711 break;
712
713 default:
714 NS_FATAL_ERROR("unknown state");
715 break;
716 }
717
718 NS_LOG_LOGIC(this << " state: " << m_state);
719}
720
721void
723{
724 NS_LOG_FUNCTION(this);
725
726 // To check if we're synchronized to this signal, we check
727 // for the CellId which is reported in the
728 // LteSpectrumSignalParametersDlCtrlFrame
729 uint16_t cellId;
730 NS_ASSERT(lteDlCtrlRxParams);
731 cellId = lteDlCtrlRxParams->cellId;
732
733 switch (m_state)
734 {
735 case TX_DATA:
736 case TX_DL_CTRL:
737 case TX_UL_SRS:
738 case RX_DATA:
739 case RX_UL_SRS:
740 NS_FATAL_ERROR("unexpected event in state " << m_state);
741 break;
742
743 case RX_DL_CTRL:
744 case IDLE:
745
746 // common code for the two states
747 // check presence of PSS for UE measuerements
748 if (lteDlCtrlRxParams->pss)
749 {
751 {
752 m_ltePhyRxPssCallback(cellId, lteDlCtrlRxParams->psd);
753 }
754 }
755
756 // differentiated code for the two states
757 switch (m_state)
758 {
759 case RX_DL_CTRL:
760 NS_ASSERT_MSG(m_cellId != cellId, "any other DlCtrl should be from a different cell");
761 NS_LOG_LOGIC(this << " ignoring other DlCtrl (cellId=" << cellId
762 << ", m_cellId=" << m_cellId << ")");
763 break;
764
765 case IDLE:
766 if (cellId == m_cellId)
767 {
768 NS_LOG_LOGIC(this << " synchronized with this signal (cellId=" << cellId << ")");
769
772 m_firstRxDuration = lteDlCtrlRxParams->duration;
773 NS_LOG_LOGIC(this << " scheduling EndRx with delay "
774 << lteDlCtrlRxParams->duration);
775
776 // store the DCIs
777 m_rxControlMessageList = lteDlCtrlRxParams->ctrlMsgList;
778 m_endRxDlCtrlEvent = Simulator::Schedule(lteDlCtrlRxParams->duration,
780 this);
782 m_interferenceCtrl->StartRx(lteDlCtrlRxParams->psd);
783 }
784 else
785 {
786 NS_LOG_LOGIC(this << " not synchronizing with this signal (cellId=" << cellId
787 << ", m_cellId=" << m_cellId << ")");
788 }
789 break;
790
791 default:
792 NS_FATAL_ERROR("unexpected event in state " << m_state);
793 break;
794 }
795 break; // case RX_DL_CTRL or IDLE
796
797 default:
798 NS_FATAL_ERROR("unknown state");
799 break;
800 }
801
802 NS_LOG_LOGIC(this << " state: " << m_state);
803}
804
805void
807{
808 NS_LOG_FUNCTION(this);
809 switch (m_state)
810 {
811 case TX_DATA:
812 case TX_DL_CTRL:
813 case TX_UL_SRS:
814 NS_FATAL_ERROR("cannot RX while TX: according to FDD channel access, the physical layer "
815 "for transmission cannot be used for reception");
816 break;
817
818 case RX_DATA:
819 case RX_DL_CTRL:
820 NS_FATAL_ERROR("cannot RX SRS while receiving something else");
821 break;
822
823 case IDLE:
824 case RX_UL_SRS:
825 // the behavior is similar when
826 // we're IDLE or RX_UL_SRS because we can receive more signals
827 // simultaneously at the eNB
828 {
829 // To check if we're synchronized to this signal, we check
830 // for the CellId which is reported in the
831 // LteSpectrumSignalParametersDlCtrlFrame
832 uint16_t cellId;
833 cellId = lteUlSrsRxParams->cellId;
834 if (cellId == m_cellId)
835 {
836 NS_LOG_LOGIC(this << " synchronized with this signal (cellId=" << cellId << ")");
837 if (m_state == IDLE)
838 {
839 // first transmission, i.e., we're IDLE and we
840 // start RX
843 m_firstRxDuration = lteUlSrsRxParams->duration;
844 NS_LOG_LOGIC(this << " scheduling EndRx with delay "
845 << lteUlSrsRxParams->duration);
846
847 m_endRxUlSrsEvent = Simulator::Schedule(lteUlSrsRxParams->duration,
849 this);
850 }
851 else if (m_state == RX_UL_SRS)
852 {
853 // sanity check: if there are multiple RX events, they
854 // should occur at the same time and have the same
855 // duration, otherwise the interference calculation
856 // won't be correct
858 (m_firstRxDuration == lteUlSrsRxParams->duration));
859 }
861 m_interferenceCtrl->StartRx(lteUlSrsRxParams->psd);
862 }
863 else
864 {
865 NS_LOG_LOGIC(this << " not in sync with this signal (cellId=" << cellId
866 << ", m_cellId=" << m_cellId << ")");
867 }
868 }
869 break;
870
871 default:
872 NS_FATAL_ERROR("unknown state");
873 break;
874 }
875
876 NS_LOG_LOGIC(this << " state: " << m_state);
877}
878
879void
881{
882 NS_LOG_FUNCTION(this << sinr);
883 m_sinrPerceived = sinr;
884}
885
886void
888 uint8_t ndi,
889 uint16_t size,
890 uint8_t mcs,
891 std::vector<int> map,
892 uint8_t layer,
893 uint8_t harqId,
894 uint8_t rv,
895 bool downlink)
896{
897 NS_LOG_FUNCTION(this << " rnti: " << rnti << " NDI " << (uint16_t)ndi << " size " << size
898 << " mcs " << (uint16_t)mcs << " layer " << (uint16_t)layer << " rv "
899 << (uint16_t)rv);
900 TbId_t tbId;
901 tbId.m_rnti = rnti;
902 tbId.m_layer = layer;
903 auto it = m_expectedTbs.find(tbId);
904 if (it != m_expectedTbs.end())
905 {
906 // might be a TB of an unreceived packet (due to high propagation losses)
907 m_expectedTbs.erase(it);
908 }
909 // insert new entry
910 tbInfo_t tbInfo = {ndi, size, mcs, map, harqId, rv, 0.0, downlink, false, false};
911 m_expectedTbs.insert(std::pair<TbId_t, tbInfo_t>(tbId, tbInfo));
912}
913
914void
916{
917 NS_LOG_FUNCTION(this << rnti);
918 TbId_t tbId;
919 tbId.m_rnti = rnti;
920 // Remove TB of both the layers
921 for (uint8_t i = 0; i < 2; i++)
922 {
923 tbId.m_layer = i;
924 auto it = m_expectedTbs.find(tbId);
925 if (it != m_expectedTbs.end())
926 {
927 m_expectedTbs.erase(it);
928 }
929 }
930}
931
932void
934{
935 NS_LOG_FUNCTION(this);
936 NS_LOG_LOGIC(this << " state: " << m_state);
937
939
940 // this will trigger CQI calculation and Error Model evaluation
941 // as a side effect, the error model should update the error status of all TBs
942 m_interferenceData->EndRx();
943 NS_LOG_DEBUG(this << " No. of burts " << m_rxPacketBurstList.size());
944 NS_LOG_DEBUG(this << " Expected TBs " << m_expectedTbs.size());
945 auto itTb = m_expectedTbs.begin();
946
947 // apply transmission mode gain
948 NS_LOG_DEBUG(this << " txMode " << (uint16_t)m_transmissionMode << " gain "
952
953 while (itTb != m_expectedTbs.end())
954 {
957 .empty()) // avoid to check for errors when there is no actual data transmitted
958 {
959 // retrieve HARQ info
960 HarqProcessInfoList_t harqInfoList;
961 if ((*itTb).second.ndi == 0)
962 {
963 // TB retxed: retrieve HARQ history
964 uint16_t ulHarqId = 0;
965 if ((*itTb).second.downlink)
966 {
967 harqInfoList =
968 m_harqPhyModule->GetHarqProcessInfoDl((*itTb).second.harqProcessId,
969 (*itTb).first.m_layer);
970 }
971 else
972 {
973 harqInfoList =
974 m_harqPhyModule->GetHarqProcessInfoUl((*itTb).first.m_rnti, ulHarqId);
975 }
976 }
978 (*itTb).second.rbBitmap,
979 (*itTb).second.size,
980 (*itTb).second.mcs,
981 harqInfoList);
982 (*itTb).second.mi = tbStats.mi;
983 (*itTb).second.corrupt = !(m_random->GetValue() > tbStats.tbler);
984 NS_LOG_DEBUG(this << "RNTI " << (*itTb).first.m_rnti << " size " << (*itTb).second.size
985 << " mcs " << (uint32_t)(*itTb).second.mcs << " bitmap "
986 << (*itTb).second.rbBitmap.size() << " layer "
987 << (uint16_t)(*itTb).first.m_layer << " TBLER " << tbStats.tbler
988 << " corrupted " << (*itTb).second.corrupt);
989 // fire traces on DL/UL reception PHY stats
991 params.m_timestamp = Simulator::Now().GetMilliSeconds();
992 params.m_cellId = m_cellId;
993 params.m_imsi = 0; // it will be set by DlPhyTransmissionCallback in LteHelper
994 params.m_rnti = (*itTb).first.m_rnti;
995 params.m_txMode = m_transmissionMode;
996 params.m_layer = (*itTb).first.m_layer;
997 params.m_mcs = (*itTb).second.mcs;
998 params.m_size = (*itTb).second.size;
999 params.m_rv = (*itTb).second.rv;
1000 params.m_ndi = (*itTb).second.ndi;
1001 params.m_correctness = (uint8_t) !(*itTb).second.corrupt;
1002 params.m_ccId = m_componentCarrierId;
1003 if ((*itTb).second.downlink)
1004 {
1005 // DL
1006 m_dlPhyReception(params);
1007 }
1008 else
1009 {
1010 // UL
1011 params.m_rv = harqInfoList.size();
1012 m_ulPhyReception(params);
1013 }
1014 }
1015
1016 itTb++;
1017 }
1018 std::map<uint16_t, DlInfoListElement_s> harqDlInfoMap;
1019 for (auto i = m_rxPacketBurstList.begin(); i != m_rxPacketBurstList.end(); ++i)
1020 {
1021 for (auto j = (*i)->Begin(); j != (*i)->End(); ++j)
1022 {
1023 // retrieve TB info of this packet
1025 (*j)->PeekPacketTag(tag);
1026 TbId_t tbId;
1027 tbId.m_rnti = tag.GetRnti();
1028 tbId.m_layer = tag.GetLayer();
1029 itTb = m_expectedTbs.find(tbId);
1030 NS_LOG_INFO(this << " Packet of " << tbId.m_rnti << " layer "
1031 << (uint16_t)tag.GetLayer());
1032 if (itTb == m_expectedTbs.end())
1033 {
1034 continue;
1035 }
1036
1037 if (!(*itTb).second.corrupt)
1038 {
1040
1042 {
1044 }
1045 }
1046 else
1047 {
1048 // TB received with errors
1050 }
1051
1052 // send HARQ feedback (if not already done for this TB)
1053 if ((*itTb).second.harqFeedbackSent)
1054 {
1055 continue;
1056 }
1057
1058 (*itTb).second.harqFeedbackSent = true;
1059 if (!(*itTb).second.downlink)
1060 {
1061 UlInfoListElement_s harqUlInfo;
1062 harqUlInfo.m_rnti = tbId.m_rnti;
1063 harqUlInfo.m_tpc = 0;
1064 if ((*itTb).second.corrupt)
1065 {
1066 harqUlInfo.m_receptionStatus = UlInfoListElement_s::NotOk;
1067 NS_LOG_DEBUG(this << " RNTI " << tbId.m_rnti << " send UL-HARQ-NACK");
1068 m_harqPhyModule->UpdateUlHarqProcessStatus(
1069 tbId.m_rnti,
1070 (*itTb).second.mi,
1071 (*itTb).second.size,
1072 (*itTb).second.size / EffectiveCodingRate[(*itTb).second.mcs]);
1073 }
1074 else
1075 {
1076 harqUlInfo.m_receptionStatus = UlInfoListElement_s::Ok;
1077 NS_LOG_DEBUG(this << " RNTI " << tbId.m_rnti << " send UL-HARQ-ACK");
1078 m_harqPhyModule->ResetUlHarqProcessStatus(tbId.m_rnti,
1079 (*itTb).second.harqProcessId);
1080 }
1082 {
1084 }
1085 }
1086 else
1087 {
1088 auto itHarq = harqDlInfoMap.find(tbId.m_rnti);
1089 if (itHarq == harqDlInfoMap.end())
1090 {
1091 DlInfoListElement_s harqDlInfo;
1093 harqDlInfo.m_rnti = tbId.m_rnti;
1094 harqDlInfo.m_harqProcessId = (*itTb).second.harqProcessId;
1095 if ((*itTb).second.corrupt)
1096 {
1097 harqDlInfo.m_harqStatus.at(tbId.m_layer) = DlInfoListElement_s::NACK;
1098 NS_LOG_DEBUG(this << " RNTI " << tbId.m_rnti << " harqId "
1099 << (uint16_t)(*itTb).second.harqProcessId << " layer "
1100 << (uint16_t)tbId.m_layer << " send DL-HARQ-NACK");
1101 m_harqPhyModule->UpdateDlHarqProcessStatus(
1102 (*itTb).second.harqProcessId,
1103 tbId.m_layer,
1104 (*itTb).second.mi,
1105 (*itTb).second.size,
1106 (*itTb).second.size / EffectiveCodingRate[(*itTb).second.mcs]);
1107 }
1108 else
1109 {
1110 harqDlInfo.m_harqStatus.at(tbId.m_layer) = DlInfoListElement_s::ACK;
1111 NS_LOG_DEBUG(this << " RNTI " << tbId.m_rnti << " harqId "
1112 << (uint16_t)(*itTb).second.harqProcessId << " layer "
1113 << (uint16_t)tbId.m_layer << " size "
1114 << (*itTb).second.size << " send DL-HARQ-ACK");
1115 m_harqPhyModule->ResetDlHarqProcessStatus((*itTb).second.harqProcessId);
1116 }
1117 harqDlInfoMap.insert(
1118 std::pair<uint16_t, DlInfoListElement_s>(tbId.m_rnti, harqDlInfo));
1119 }
1120 else
1121 {
1122 if ((*itTb).second.corrupt)
1123 {
1124 (*itHarq).second.m_harqStatus.at(tbId.m_layer) = DlInfoListElement_s::NACK;
1125 NS_LOG_DEBUG(this << " RNTI " << tbId.m_rnti << " harqId "
1126 << (uint16_t)(*itTb).second.harqProcessId << " layer "
1127 << (uint16_t)tbId.m_layer << " size "
1128 << (*itHarq).second.m_harqStatus.size()
1129 << " send DL-HARQ-NACK");
1130 m_harqPhyModule->UpdateDlHarqProcessStatus(
1131 (*itTb).second.harqProcessId,
1132 tbId.m_layer,
1133 (*itTb).second.mi,
1134 (*itTb).second.size,
1135 (*itTb).second.size / EffectiveCodingRate[(*itTb).second.mcs]);
1136 }
1137 else
1138 {
1139 NS_ASSERT_MSG(tbId.m_layer < (*itHarq).second.m_harqStatus.size(),
1140 " layer " << (uint16_t)tbId.m_layer);
1141 (*itHarq).second.m_harqStatus.at(tbId.m_layer) = DlInfoListElement_s::ACK;
1142 NS_LOG_DEBUG(this << " RNTI " << tbId.m_rnti << " harqId "
1143 << (uint16_t)(*itTb).second.harqProcessId << " layer "
1144 << (uint16_t)tbId.m_layer << " size "
1145 << (*itHarq).second.m_harqStatus.size()
1146 << " send DL-HARQ-ACK");
1147 m_harqPhyModule->ResetDlHarqProcessStatus((*itTb).second.harqProcessId);
1148 }
1149 }
1150 } // end if ((*itTb).second.downlink) HARQ
1151 }
1152 }
1153
1154 // send DL HARQ feedback to LtePhy
1155 for (auto itHarq = harqDlInfoMap.begin(); itHarq != harqDlInfoMap.end(); itHarq++)
1156 {
1158 {
1159 m_ltePhyDlHarqFeedbackCallback((*itHarq).second);
1160 }
1161 }
1162 // forward control messages of this frame to LtePhy
1163 if (!m_rxControlMessageList.empty())
1164 {
1166 {
1168 }
1169 }
1171 m_rxPacketBurstList.clear();
1172 m_rxControlMessageList.clear();
1173 m_expectedTbs.clear();
1174}
1175
1176void
1178{
1179 NS_LOG_FUNCTION(this);
1180 NS_LOG_LOGIC(this << " state: " << m_state);
1181
1183
1184 // this will trigger CQI calculation and Error Model evaluation
1185 // as a side effect, the error model should update the error status of all TBs
1186 m_interferenceCtrl->EndRx();
1187 // apply transmission mode gain
1188 NS_LOG_DEBUG(this << " txMode " << (uint16_t)m_transmissionMode << " gain "
1191 if (m_transmissionMode > 0)
1192 {
1193 // in case of MIMO, ctrl is always txed as TX diversity
1195 }
1196 // m_sinrPerceived *= m_txModeGain.at (m_transmissionMode);
1197 bool error = false;
1199 {
1201 error = !(m_random->GetValue() > errorRate);
1202 NS_LOG_DEBUG(this << " PCFICH-PDCCH Decodification, errorRate " << errorRate << " error "
1203 << error);
1204 }
1205
1206 if (!error)
1207 {
1209 {
1210 NS_LOG_DEBUG(this << " PCFICH-PDCCH Rxed OK");
1212 }
1213 }
1214 else
1215 {
1217 {
1218 NS_LOG_DEBUG(this << " PCFICH-PDCCH Error");
1220 }
1221 }
1223 m_rxControlMessageList.clear();
1224}
1225
1226void
1228{
1231 m_interferenceCtrl->EndRx();
1232 // nothing to do (used only for SRS at this stage)
1233}
1234
1235void
1237{
1238 m_cellId = cellId;
1239}
1240
1241void
1242LteSpectrumPhy::SetComponentCarrierId(uint8_t componentCarrierId)
1243{
1244 m_componentCarrierId = componentCarrierId;
1245}
1246
1247void
1252
1253void
1258
1259void
1264
1265void
1270
1271void
1276
1277void
1282
1283void
1285{
1286 NS_LOG_FUNCTION(this << (uint16_t)txMode);
1287 NS_ASSERT_MSG(txMode < m_txModeGain.size(),
1288 "TransmissionMode not available: 1.." << m_txModeGain.size());
1289 m_transmissionMode = txMode;
1291}
1292
1293void
1294LteSpectrumPhy::SetTxModeGain(uint8_t txMode, double gain)
1295{
1296 NS_LOG_FUNCTION(this << " txmode " << (uint16_t)txMode << " gain " << gain);
1297 if (txMode > 0)
1298 {
1299 // convert to linear
1300 double gainLin = std::pow(10.0, (gain / 10.0));
1301 if (m_txModeGain.size() < txMode)
1302 {
1303 m_txModeGain.resize(txMode);
1304 }
1305 m_txModeGain.at(txMode - 1) = gainLin;
1306 }
1307}
1308
1309int64_t
1311{
1312 NS_LOG_FUNCTION(this << stream);
1313 m_random->SetStream(stream);
1314 return 1;
1315}
1316
1317} // namespace ns3
AttributeValue implementation for Boolean.
Definition boolean.h:26
bool IsNull() const
Check for null implementation.
Definition callback.h:555
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
static TbStats_t GetTbDecodificationStats(const SpectrumValue &sinr, const std::vector< int > &map, uint16_t size, uint8_t mcs, HarqProcessInfoList_t miHistory)
run the error-model algorithm for the specified TB
static double GetPcfichPdcchError(const SpectrumValue &sinr)
run the error-model algorithm for the specified PCFICH+PDCCH channels
Tag used to define the RNTI and LC id for each MAC packet transmitted.
uint16_t GetRnti() const
Get RNTI function.
uint8_t GetLayer() const
Get layer function.
The LteSpectrumPhy models the physical layer of LTE.
void RemoveExpectedTb(uint16_t rnti)
Remove expected transport block.
Ptr< const SpectrumModel > m_rxSpectrumModel
the spectrum model
TracedCallback< Ptr< const PacketBurst > > m_phyTxEndTrace
the phy transmit end trace callback
bool m_dataErrorModelEnabled
when true (default) the phy error model is enabled
void SetState(State newState)
Set the state of the phy layer.
Ptr< LteInterference > m_interferenceData
the data interference
uint8_t m_transmissionMode
for UEs: store the transmission mode
EventId m_endRxDlCtrlEvent
end receive DL control event
void AddCtrlSinrChunkProcessor(Ptr< LteChunkProcessor > p)
void AddDataSinrChunkProcessor(Ptr< LteChunkProcessor > p)
LtePhyUlHarqFeedbackCallback m_ltePhyUlHarqFeedbackCallback
the LTE phy UL HARQ feedback callback
void AddExpectedTb(uint16_t rnti, uint8_t ndi, uint16_t size, uint8_t mcs, std::vector< int > map, uint8_t layer, uint8_t harqId, uint8_t rv, bool downlink)
Ptr< MobilityModel > GetMobility() const override
Get the associated MobilityModel instance.
Ptr< const SpectrumModel > GetRxSpectrumModel() const override
void SetHarqPhyModule(Ptr< LteHarqPhy > harq)
Set HARQ phy function.
LtePhyRxPssCallback m_ltePhyRxPssCallback
the LTE phy receive PSS callback
void StartRxDlCtrl(Ptr< LteSpectrumSignalParametersDlCtrlFrame > lteDlCtrlRxParams)
Start receive DL control function.
void StartRxUlSrs(Ptr< LteSpectrumSignalParametersUlSrsFrame > lteUlSrsRxParams)
Start receive UL SRS function.
void AddDataPowerChunkProcessor(Ptr< LteChunkProcessor > p)
EventId m_endRxDataEvent
end receive data event
void SetLtePhyRxPssCallback(LtePhyRxPssCallback c)
set the callback for the reception of the PSS as part of the interconnections between the LteSpectrum...
void SetAntenna(Ptr< AntennaModel > a)
set the AntennaModel to be used
bool StartTxDataFrame(Ptr< PacketBurst > pb, std::list< Ptr< LteControlMessage > > ctrlMsgList, Time duration)
Start a transmission of data frame in DL and UL.
void StartRxData(Ptr< LteSpectrumSignalParametersDataFrame > params)
Start receive data function.
TracedCallback< PhyReceptionStatParameters > m_dlPhyReception
Trace information regarding PHY stats from DL Rx perspective PhyReceptionStatParameters (see lte-comm...
Ptr< NetDevice > m_device
the device
Ptr< SpectrumChannel > GetChannel()
TracedCallback< Ptr< const PacketBurst > > m_phyTxStartTrace
the phy transmit start trace callback
void DoDispose() override
Destructor implementation.
void EndTxData()
End transmit data function.
void SetTransmissionMode(uint8_t txMode)
void SetLtePhyRxDataEndErrorCallback(LtePhyRxDataEndErrorCallback c)
set the callback for the end of a RX in error, as part of the interconnections between the PHY and th...
SpectrumValue m_sinrPerceived
the preceived SINR
Ptr< SpectrumValue > m_txPsd
the transmit PSD
void AddInterferenceDataChunkProcessor(Ptr< LteChunkProcessor > p)
LteChunkProcessor devoted to evaluate interference + noise power in data symbols of the subframe.
void SetDevice(Ptr< NetDevice > d) override
Set the associated NetDevice instance.
void ChangeState(State newState)
Change state function.
void SetTxModeGain(uint8_t txMode, double gain)
Set transmit mode gain function.
std::vector< double > m_txModeGain
duplicate value of LteUePhy
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
Ptr< NetDevice > GetDevice() const override
Get the associated NetDevice instance.
Time m_firstRxStart
the first receive start
Ptr< LteHarqPhy > m_harqPhyModule
the HARQ phy module
void SetLtePhyRxDataEndOkCallback(LtePhyRxDataEndOkCallback c)
set the callback for the successful end of a RX, as part of the interconnections between the PHY and ...
void EndRxUlSrs()
End receive UL SRS function.
void SetLtePhyUlHarqFeedbackCallback(LtePhyUlHarqFeedbackCallback c)
set the callback for the UL HARQ feedback as part of the interconnections between the LteSpectrumPhy ...
void SetChannel(Ptr< SpectrumChannel > c) override
Set the channel attached to this device.
void SetComponentCarrierId(uint8_t componentCarrierId)
TracedCallback< Ptr< const PacketBurst > > m_phyRxStartTrace
the phy receive start trace callback
expectedTbs_t m_expectedTbs
the expected TBS
void EndTxUlSrs()
End transmit UL SRS function.
void SetNoisePowerSpectralDensity(Ptr< const SpectrumValue > noisePsd)
set the noise power spectral density
void UpdateSinrPerceived(const SpectrumValue &sinr)
Ptr< SpectrumChannel > m_channel
the channel
void EndRxDlCtrl()
End receive DL control function.
void SetTxPowerSpectralDensity(Ptr< SpectrumValue > txPsd)
set the Power Spectral Density of outgoing signals in W/Hz.
EventId m_endTxEvent
end transmit event
LtePhyRxDataEndOkCallback m_ltePhyRxDataEndOkCallback
the LTE phy receive data end ok callback
void SetLtePhyRxCtrlEndErrorCallback(LtePhyRxCtrlEndErrorCallback c)
set the callback for the erroneous end of a RX ctrl frame, as part of the interconnections between th...
uint16_t m_cellId
the cell ID
Ptr< AntennaModel > m_antenna
the antenna model
void SetLtePhyDlHarqFeedbackCallback(LtePhyDlHarqFeedbackCallback c)
set the callback for the DL HARQ feedback as part of the interconnections between the LteSpectrumPhy ...
Time m_firstRxDuration
the first receive duration
Ptr< PacketBurst > m_txPacketBurst
the transmit packet burst
uint8_t m_componentCarrierId
the component carrier ID
void StartRx(Ptr< SpectrumSignalParameters > params) override
Notify the SpectrumPhy instance of an incoming signal.
Ptr< Object > GetAntenna() const override
Get the AntennaModel used by this SpectrumPhy instance for transmission and/or reception.
LtePhyRxDataEndErrorCallback m_ltePhyRxDataEndErrorCallback
the LTE phy receive data end error callback
bool StartTxDlCtrlFrame(std::list< Ptr< LteControlMessage > > ctrlMsgList, bool pss)
Start a transmission of control frame in DL.
static TypeId GetTypeId()
Get the type ID.
uint8_t m_layersNum
layers num
Ptr< MobilityModel > m_mobility
the modility model
TracedCallback< PhyReceptionStatParameters > m_ulPhyReception
Trace information regarding PHY stats from UL Rx perspective PhyReceptionStatParameters (see lte-comm...
void SetMobility(Ptr< MobilityModel > m) override
Set the mobility model associated with this device.
LtePhyDlHarqFeedbackCallback m_ltePhyDlHarqFeedbackCallback
the LTE phy DL HARQ feedback callback
void EndTxDlCtrl()
End transmit DL control function.
std::list< Ptr< LteControlMessage > > m_rxControlMessageList
the receive control message list
void AddRsPowerChunkProcessor(Ptr< LteChunkProcessor > p)
Ptr< LteInterference > m_interferenceCtrl
the control interference
TracedCallback< Ptr< const Packet > > m_phyRxEndErrorTrace
the phy receive end error trace callback
void EndRxData()
End receive data function.
std::list< Ptr< LteControlMessage > > m_txControlMessageList
the transmit control message list
bool m_ctrlErrorModelEnabled
when true (default) the phy error model is enabled for DL ctrl frame
std::list< Ptr< PacketBurst > > m_rxPacketBurstList
the receive burst list
void AddInterferenceCtrlChunkProcessor(Ptr< LteChunkProcessor > p)
LteChunkProcessor devoted to evaluate interference + noise power in control symbols of the subframe.
TracedCallback< Ptr< const Packet > > m_phyRxEndOkTrace
the phy receive end ok trace callback
bool StartTxUlSrsFrame()
Start a transmission of control frame in UL.
LtePhyRxCtrlEndErrorCallback m_ltePhyRxCtrlEndErrorCallback
the LTE phy receive control end error callback
void SetLtePhyRxCtrlEndOkCallback(LtePhyRxCtrlEndOkCallback c)
set the callback for the successful end of a RX ctrl frame, as part of the interconnections between t...
void Reset()
reset the internal state
EventId m_endRxUlSrsEvent
end receive UL SRS event
void SetCellId(uint16_t cellId)
LtePhyRxCtrlEndOkCallback m_ltePhyRxCtrlEndOkCallback
the LTE phy receive control end ok callback
Ptr< UniformRandomVariable > m_random
Provides uniform random variables.
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Abstract base class for Spectrum-aware PHY layers.
Set of values corresponding to a given SpectrumModel.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:397
@ S
second
Definition nstime.h:105
static uint8_t TxMode2LayerNum(uint8_t txMode)
Transmit mode 2 layer number.
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1380
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
bool operator==(const EventId &a, const EventId &b)
Definition event-id.h:155
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
bool operator<(const EventId &a, const EventId &b)
Definition event-id.h:168
std::vector< HarqProcessInfoElement_t > HarqProcessInfoList_t
HarqProcessInfoList_t typedef.
static const Time DL_CTRL_DURATION
duration of the control portion of a subframe = 0.001 / 14 * 3 (ctrl fixed to 3 symbols) -1ns as marg...
static const Time UL_SRS_DURATION
duration of SRS portion of UL subframe = 1 symbol for SRS -1ns as margin to avoid overlapping simulat...
static const double EffectiveCodingRate[29]
Effective coding rate.
@ IDLE
Channel is IDLE, no packet is being transmitted.
See section 4.3.23 dlInfoListElement.
uint8_t m_harqProcessId
HARQ process ID.
std::vector< HarqStatus_e > m_harqStatus
HARQ status.
PhyReceptionStatParameters structure.
Definition lte-common.h:201
TbId_t structure.
uint8_t m_layer
layer
uint16_t m_rnti
RNTI.
TbStats_t structure.
double mi
Mutual information.
double tbler
Transport block BLER.
See section 4.3.12 ulInfoListElement.
uint8_t m_tpc
Tx power control command.
tbInfo_t structure