7#include "lena-error-model.h"
8#include "nr-error-model.h"
9#include "nr-lte-mi-error-model.h"
11#include <ns3/double.h>
15#include <ns3/nr-spectrum-value-helper.h>
16#include <ns3/object-factory.h>
17#include <ns3/uinteger.h>
22NS_LOG_COMPONENT_DEFINE(
"NrAmc");
23NS_OBJECT_ENSURE_REGISTERED(NrAmc);
27 NS_LOG_INFO(
"Initialize AMC module");
37 NS_LOG_FUNCTION(
this);
44 NS_LOG_FUNCTION(
this);
54 .AddAttribute(
"NumRefScPerRb",
55 "Number of Subcarriers carrying Reference Signals per RB",
58 MakeUintegerChecker<uint8_t>(0, 12))
59 .AddAttribute(
"AmcModel",
60 "AMC model used to assign CQI",
67 .AddAttribute(
"ErrorModelType",
68 "Type of the Error Model to use when AmcModel is set to ErrorModel. "
69 "This parameter has to match the ErrorModelType in nr-spectrum-model,"
70 "because they need to refer to same MCS tables and indexes",
74 .AddConstructor<NrAmc>();
88 NS_ASSERT_MSG(cqi >= 0 && cqi <= 15,
"CQI must be in [0..15] = " << cqi);
90 double spectralEfficiency = m_errorModel->GetSpectralEfficiencyForCqi(cqi);
93 while ((mcs < m_errorModel->
GetMaxMcs()) &&
94 (m_errorModel->GetSpectralEfficiencyForMcs(mcs + 1) <= spectralEfficiency))
99 NS_LOG_LOGIC(
"mcs = " << mcs);
107 NS_LOG_FUNCTION(
this);
108 return m_numRefScPerRb;
114 NS_LOG_FUNCTION(
this);
115 m_numRefScPerRb = nref;
121 NS_LOG_FUNCTION(
this <<
static_cast<uint32_t
>(mcs));
123 NS_ASSERT_MSG(mcs <= m_errorModel->
GetMaxMcs(),
124 "MCS=" <<
static_cast<uint32_t
>(mcs) <<
" while maximum MCS is "
125 <<
static_cast<uint32_t
>(m_errorModel->GetMaxMcs()));
128 uint32_t tbSize = payloadSize;
132 if (payloadSize >= m_crcLen)
135 payloadSize - m_crcLen;
138 m_errorModel->GetMaxCbSize(payloadSize,
142 double C = ceil(tbSize / cbSize);
143 tbSize = payloadSize -
static_cast<uint32_t
>(
149 NS_LOG_INFO(
" mcs:" << (
unsigned)mcs <<
" TB size:" << tbSize);
168 NS_LOG_FUNCTION(
this);
176 Values::const_iterator it;
180 double m_ber = GetBer();
182 for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
184 double sinr_ = (*it);
199 double s = log2(1 + (sinr_ / ((-std::log(5.0 * m_ber)) / 1.5)));
205 NS_LOG_LOGIC(
" PRB =" << sinr.GetSpectrumModel()->GetNumBands() <<
", sinr = "
206 << sinr_ <<
" (=" << 10 * std::log10(sinr_) <<
" dB)"
207 <<
", spectral efficiency =" << s <<
", CQI = " << cqi_
208 <<
", BER = " << m_ber);
221 std::vector<int> rbMap;
223 for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
227 rbMap.push_back(rbId);
233 Ptr<NrErrorModelOutput> output;
238 output = m_errorModel->GetTbDecodificationStats(sinr,
243 if (output->m_tbler > 0.1)
255 if ((output->m_tbler > 0.1) && (mcs == 0))
259 else if (mcs == m_errorModel->GetMaxMcs())
265 double s = m_errorModel->GetSpectralEfficiencyForMcs(mcs);
267 while ((cqi < 15) && (m_errorModel->GetSpectralEfficiencyForCqi(cqi + 1) <= s))
272 NS_LOG_DEBUG(
this <<
"\t MCS " << (uint16_t)mcs <<
"-> CQI " << cqi);
281 NS_ASSERT_MSG(s >= 0.0,
"negative spectral efficiency = " << s);
283 while ((cqi < 15) && (m_errorModel->GetSpectralEfficiencyForCqi(cqi + 1) < s))
287 NS_LOG_LOGIC(
"cqi = " << cqi);
295 NS_ASSERT_MSG(s >= 0.0,
"negative spectral efficiency = " << s);
297 while ((mcs < m_errorModel->
GetMaxMcs()) &&
298 (m_errorModel->GetSpectralEfficiencyForMcs(mcs + 1) < s))
302 NS_LOG_LOGIC(
"cqi = " << mcs);
309 NS_LOG_FUNCTION(
this);
310 return m_errorModel->GetMaxMcs();
316 NS_LOG_FUNCTION(
this);
323 NS_LOG_FUNCTION(
this);
330 NS_LOG_FUNCTION(
this);
331 ObjectFactory factory;
332 m_errorModelType = type;
334 factory.SetTypeId(m_errorModelType);
335 m_errorModel = DynamicCast<NrErrorModel>(factory.Create());
336 NS_ASSERT(m_errorModel !=
nullptr);
342 NS_LOG_FUNCTION(
this);
343 return m_errorModelType;
349 NS_LOG_FUNCTION(
this);
364 auto mcs = uint8_t{0};
368 NS_ABORT_MSG(
"ShannonModel is not yet supported");
371 mcs = GetMaxMcsForErrorModel(sinrMat);
374 NS_ABORT_MSG(
"AMC model not supported");
377 auto wbCqi = GetWbCqiFromMcs(mcs);
378 auto nRbs = sinrMat.GetNumRbs();
379 auto nSbs = (nRbs + subbandSize - 1) / subbandSize;
383 auto sbCqis = std::vector<uint8_t>(nSbs, wbCqi);
385 auto tbSize = CalcTbSizeForMimoMatrix(mcs, sinrMat);
386 return McsParams{mcs, wbCqi, sbCqis, tbSize};
390NrAmc::GetMaxMcsForErrorModel(
const NrSinrMatrix& sinrMat)
const
392 auto mcs = uint8_t{0};
395 auto tbler = CalcTblerForMimoMatrix(mcs, sinrMat);
414NrAmc::GetWbCqiFromMcs(uint8_t mcs)
const
417 auto cqi = uint8_t{0};
422 else if (mcs == m_errorModel->GetMaxMcs())
429 auto s = m_errorModel->GetSpectralEfficiencyForMcs(mcs);
432 while ((cqi < 15) && (m_errorModel->GetSpectralEfficiencyForCqi(cqi + 1) <= s))
441NrAmc::CalcTblerForMimoMatrix(uint8_t mcs,
const NrSinrMatrix& sinrMat)
const
443 auto dummyRnti = uint16_t{0};
444 auto duration = Time{1.0};
445 auto mimoChunk = MimoSinrChunk{sinrMat, dummyRnti, duration};
446 auto mimoChunks = std::vector<MimoSinrChunk>{mimoChunk};
447 auto rank = sinrMat.GetRank();
450 std::vector<int> rbMap{};
451 int nRbs =
static_cast<int>(sinrMat.GetNumRbs());
452 for (
int rbIdx = 0; rbIdx < nRbs; rbIdx++)
454 if (sinrMat(0, rbIdx) != 0.0)
456 rbMap.push_back(rbIdx);
460 auto tbSize = CalcTbSizeForMimoMatrix(mcs, sinrMat);
462 auto outputOfEm = m_errorModel->GetTbDecodificationStatsMimo(mimoChunks,
468 return outputOfEm->m_tbler;
472NrAmc::CalcTbSizeForMimoMatrix(uint8_t mcs,
const NrSinrMatrix& sinrMat)
const
474 auto nRbs = sinrMat.GetNumRbs();
476 auto rank = sinrMat.GetRank();
static TypeId GetTypeId()
GetTypeId.
void SetErrorModelType(const TypeId &type)
Set Error model type.
void SetAmcModel(AmcModel m)
Set the AMC model type.
TypeId GetErrorModelType() const
Get the error model type.
uint8_t GetNumRefScPerRb() const
NrAmc()
NrAmc constructor.
void SetUlMode()
Set the object to be in "UL" mode.
static TypeId GetTypeId()
GetTypeId.
AmcModel GetAmcModel() const
Get the AMC model type.
uint32_t GetPayloadSize(uint8_t mcs, uint8_t rank, uint32_t nprb) const
Calculate the Payload Size (in bytes) from MCS and the number of RB.
static constexpr size_t NR_AMC_NUM_SYMBOLS_DEFAULT
Num OFDM syms for TB size.
uint8_t CreateCqiFeedbackWbTdma(const SpectrumValue &sinr, uint8_t &mcsWb) const
Create a CQI/MCS wideband feedback from a SINR values.
McsParams GetMaxMcsParams(const NrSinrMatrix &sinrMat, size_t subbandSize) const
Find maximum MCS supported for this channel and obtain related parameters.
uint32_t CalculateTbSize(uint8_t mcs, uint8_t rank, uint32_t nprb) const
Calculate the TransportBlock size (in bytes) giving the MCS and the number of RB assigned.
void SetDlMode()
Set the object to be in "DL" mode.
uint8_t GetCqiFromSpectralEfficiency(double s) const
Get CQI from a SpectralEfficiency value.
uint8_t GetMcsFromSpectralEfficiency(double s) const
Get MCS from a SpectralEfficiency value.
AmcModel
Valid types of the model used to create a cqi feedback.
@ ErrorModel
Error Model version (can use different error models, see NrErrorModel)
@ ShannonModel
Shannon based model (very conservative)
void SetNumRefScPerRb(uint8_t nref)
Set the the number of subcarriers carrying reference signals per resource block.
uint8_t GetMcsFromCqi(uint8_t cqi) const
Get the MCS value from a CQI value.
uint32_t GetMaxMcs() const
Get the maximum MCS (depends on the underlying error model)
~NrAmc() override
~NrAmc deconstructor
TypeId GetInstanceTypeId() const override
GetInstanceTypeId.
std::vector< Ptr< NrErrorModelOutput > > NrErrorModelHistory
Vector of previous output.
static TypeId GetTypeId()
GetTypeId.
NrSinrMatrix stores the MIMO SINR matrix, with dimension rank x nRbs.
static const uint8_t SUBCARRIERS_PER_RB
subcarriers per resource block
Parameters related to MCS selection.