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>();
82 NS_ASSERT_MSG(cqi >= 0 && cqi <= 15,
"CQI must be in [0..15] = " << cqi);
84 if (m_cachedCqiToMcsMap.find(cqi) == m_cachedCqiToMcsMap.end())
86 double spectralEfficiency = m_errorModel->GetSpectralEfficiencyForCqi(cqi);
89 while ((mcs < m_errorModel->
GetMaxMcs()) &&
90 (m_errorModel->GetSpectralEfficiencyForMcs(mcs + 1) <= spectralEfficiency))
94 NS_LOG_LOGIC(
"mcs = " << mcs);
95 m_cachedCqiToMcsMap[cqi] = mcs;
98 return m_cachedCqiToMcsMap.at(cqi);
104 NS_LOG_FUNCTION(
this);
105 return m_numRefScPerRb;
111 NS_LOG_FUNCTION(
this);
112 m_numRefScPerRb = nref;
118 NS_LOG_FUNCTION(
this <<
static_cast<uint32_t
>(mcs));
120 NS_ASSERT_MSG(mcs <= m_errorModel->
GetMaxMcs(),
121 "MCS=" <<
static_cast<uint32_t
>(mcs) <<
" while maximum MCS is "
122 <<
static_cast<uint32_t
>(m_errorModel->GetMaxMcs()));
125 uint32_t tbSize = payloadSize;
129 if (payloadSize >= m_crcLen)
132 payloadSize - m_crcLen;
135 m_errorModel->GetMaxCbSize(payloadSize,
139 double C = ceil(tbSize / cbSize);
140 tbSize = payloadSize -
static_cast<uint32_t
>(
146 NS_LOG_INFO(
" mcs:" << (
unsigned)mcs <<
" TB size:" << tbSize);
165 NS_LOG_FUNCTION(
this);
173 Values::const_iterator it;
177 double m_ber = GetBer();
179 for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
181 double sinr_ = (*it);
194 NS_LOG_LOGIC(
" PRB =" << sinr.GetSpectrumModel()->GetNumBands() <<
", sinr = "
195 << sinr_ <<
" (=" << 10 * std::log10(sinr_) <<
" dB)"
196 <<
", spectral efficiency =" << s <<
", CQI = " << cqi_
197 <<
", BER = " << m_ber);
210 std::vector<int> rbMap;
212 for (it = sinr.ConstValuesBegin(); it != sinr.ConstValuesEnd(); it++)
216 rbMap.push_back(rbId);
222 Ptr<NrErrorModelOutput> output;
227 output = m_errorModel->GetTbDecodificationStats(sinr,
232 if (output->m_tbler > 0.1)
244 if ((output->m_tbler > 0.1) && (mcs == 0))
248 else if (mcs == m_errorModel->GetMaxMcs())
254 double s = m_errorModel->GetSpectralEfficiencyForMcs(mcs);
256 while ((cqi < 15) && (m_errorModel->GetSpectralEfficiencyForCqi(cqi + 1) <= s))
261 NS_LOG_DEBUG(
this <<
"\t MCS " << (uint16_t)mcs <<
"-> CQI " << cqi);
270 NS_ASSERT_MSG(s >= 0.0,
"negative spectral efficiency = " << s);
272 while ((cqi < 15) && (m_errorModel->GetSpectralEfficiencyForCqi(cqi + 1) < s))
276 NS_LOG_LOGIC(
"cqi = " << cqi);
284 NS_ASSERT_MSG(s >= 0.0,
"negative spectral efficiency = " << s);
286 while ((mcs < m_errorModel->
GetMaxMcs()) &&
287 (m_errorModel->GetSpectralEfficiencyForMcs(mcs + 1) < s))
291 NS_LOG_LOGIC(
"cqi = " << mcs);
298 NS_LOG_FUNCTION(
this);
299 return m_errorModel->GetMaxMcs();
305 NS_LOG_FUNCTION(
this);
312 NS_LOG_FUNCTION(
this);
319 NS_LOG_FUNCTION(
this);
320 ObjectFactory factory;
321 m_errorModelType = type;
323 factory.SetTypeId(m_errorModelType);
324 m_errorModel = DynamicCast<NrErrorModel>(factory.Create());
325 NS_ASSERT(m_errorModel !=
nullptr);
326 m_cachedCqiToMcsMap.clear();
332 NS_LOG_FUNCTION(
this);
333 return m_errorModelType;
339 NS_LOG_FUNCTION(
this);
354 auto wbMcs =
GetMcs(sinrMat);
355 auto wbCqi = GetWbCqiFromMcs(wbMcs);
356 auto sbMcs =
GetSbMcs(subbandSize, sinrMat);
358 std::vector<uint8_t> sbCqis;
359 sbCqis.resize(sbMcs.size());
361 std::transform(sbMcs.begin(), sbMcs.end(), sbCqis.begin(), [&](uint8_t mcs) {
362 return GetWbCqiFromMcs(mcs);
365 auto tbSize = CalcTbSizeForMimoMatrix(wbMcs, sinrMat);
366 return McsParams{wbMcs, wbCqi, sbCqis, tbSize};
372 auto nRbs = sinrMat.GetNumRbs();
373 auto nSbs = (nRbs + subbandSize - 1) / subbandSize;
374 auto sbMcs = std::vector<uint8_t>(nSbs, 0);
376 size_t lastSubbandSize = sinrMat.GetNumCols() % subbandSize;
377 for (
size_t i = 0; i < sbMcs.size(); i++)
379 auto sinrSb =
ExtractSbFromMat(i, i != (nSbs - 1) ? subbandSize : lastSubbandSize, sinrMat);
380 sbMcs[i] =
GetMcs(sinrSb);
387 const size_t subbandSize,
390 const auto rank = sinrMat.GetNumRows();
391 DoubleMatrixArray sinrSb(rank, sinrMat.GetNumCols());
392 for (uint8_t r = 0; r < rank; r++)
394 for (
size_t iRb = sbIndex * subbandSize; iRb < (sbIndex + 1) * subbandSize; iRb++)
396 sinrSb(r, iRb) = sinrMat(r, iRb);
405 auto sbSinrMat = DoubleMatrixArray{sinrMat.GetNumRows(), sinrMat.GetNumCols()};
406 for (
size_t iRb = 0; iRb < sinrMat.GetNumCols(); iRb++)
408 for (
size_t layer = 0; layer < sinrMat.GetNumRows(); layer++)
410 sbSinrMat(layer, iRb) = avgSinrSb(layer, 0);
420 auto mcs = uint8_t{0};
424 NS_ABORT_MSG(
"ShannonModel is not yet supported");
427 mcs = GetMaxMcsForErrorModel(sinrMat);
430 NS_ABORT_MSG(
"AMC model not supported");
437NrAmc::GetMaxMcsForErrorModel(
const NrSinrMatrix& sinrMat)
const
439 auto mcs = uint8_t{0};
442 auto tbler = CalcTblerForMimoMatrix(mcs, sinrMat);
461NrAmc::GetWbCqiFromMcs(uint8_t mcs)
const
464 auto cqi = uint8_t{0};
469 else if (mcs == m_errorModel->GetMaxMcs())
476 auto s = m_errorModel->GetSpectralEfficiencyForMcs(mcs);
479 while ((cqi < 15) && (m_errorModel->GetSpectralEfficiencyForCqi(cqi + 1) <= s))
488NrAmc::CalcTblerForMimoMatrix(uint8_t mcs,
const NrSinrMatrix& sinrMat)
const
490 auto dummyRnti = uint16_t{0};
491 auto duration = Time{1.0};
492 auto mimoChunk = MimoSinrChunk{sinrMat, dummyRnti, duration};
493 auto mimoChunks = std::vector<MimoSinrChunk>{mimoChunk};
494 auto rank = sinrMat.GetRank();
497 std::vector<int> rbMap{};
498 int nRbs =
static_cast<int>(sinrMat.GetNumRbs());
499 for (
int rbIdx = 0; rbIdx < nRbs; rbIdx++)
501 if (sinrMat(0, rbIdx) != 0.0)
503 rbMap.push_back(rbIdx);
512 auto tbSize = CalcTbSizeForMimoMatrix(mcs, sinrMat);
514 auto outputOfEm = m_errorModel->GetTbDecodificationStatsMimo(mimoChunks,
520 return outputOfEm->m_tbler;
524NrAmc::CalcTbSizeForMimoMatrix(uint8_t mcs,
const NrSinrMatrix& sinrMat)
const
526 auto nRbs = sinrMat.GetNumRbs();
528 auto rank = sinrMat.GetRank();
542 double s = log2(1 + (sinr / ((-std::log(5.0 * GetBer())) / 1.5)));
554 double sinr = (pow(2, spectralEff) - 1) * (-std::log(5.0 * GetBer())) / 1.5;
static TypeId GetTypeId()
GetTypeId.
void SetErrorModelType(const TypeId &type)
Set Error model type.
void SetAmcModel(AmcModel m)
Set the AMC model type.
std::vector< uint8_t > GetSbMcs(const size_t subbandSize, const NrSinrMatrix &sinrMat) const
Find Sb MCS supported for this channel.
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.
double GetSpectralEfficiencyForSinr(double sinr) const
Compute spectral efficient for a given SINR according to Shannon's capacity.
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.
NrSinrMatrix ExtractSbFromMat(const uint8_t sbIndex, const size_t subbandSize, const NrSinrMatrix &sinrMat) const
Extract sub-band sinr value from the sinrMatrix.
NrSinrMatrix CreateSinrMatForSb(const NrSinrMatrix &avgSinrSb, const NrSinrMatrix &sinrMat) const
Create wide-band matrix based on average sinr of particular sub-band.
double GetSinrFromSpectralEfficiency(double spectralEff) const
Compute SINR for a given spectral efficiency according to Shannon's capacity.
static constexpr size_t NR_AMC_NUM_SYMBOLS_DEFAULT
Num OFDM syms for TB size.
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.
uint8_t CreateCqiFeedbackSiso(const SpectrumValue &sinr, uint8_t &mcsWb) const
Create a CQI/MCS wideband feedback from SINR values.
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.
uint8_t GetMcs(const NrSinrMatrix &sinrMat) const
Find MCS supported for this channel.
uint32_t GetMaxMcs() const
Get the maximum MCS (depends on the underlying error model)
~NrAmc() override
~NrAmc deconstructor
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.