From 9317c14999d5fb6fb0474dd676b6d9502e68dd0a Mon Sep 17 00:00:00 2001 From: tabgab Date: Sun, 8 Nov 2026 13:48:37 +0200 Subject: [PATCH] common, phy: DL_NUM_TXMODE and UL_NUM_TXMODE follow the TxMode enum The MIMO transmission modes were removed and TxMode shrank to SINGLE_ANTENNA_PORT0, TRANSMIT_DIVERSITY and the UNKNOWN_TX_MODE sentinel, but the two count constants stayed at 6. LteFeedbackComputationRealistic sizes its per-mode feedback vectors with DL_NUM_TXMODE and stores (TxMode)z for every index, so it wrote 3, 4 and 5 into a TxMode. 3 is not an enumerator, and 4 and 5 are outside the enum's representable range, 0..3 (undefined behaviour; UBSan reports the loads in LteFeedback::setTxMode and LteFeedback::isEmptyFeedback). The AMC also allocated and scanned feedback history buffers for four modes that no longer exist. The constants now take their value from UNKNOWN_TX_MODE, and the loop of the per-remote feedback computation that excluded the removed last mode (MULTI_USER) runs over every mode. The empty feedbacks of the stale modes were never pushed to the AMC, so the fingerprints do not move. tests/unit/TxModeCount.test checks the constants against the enum and that every feedback the realistic computation returns carries a valid TxMode, one entry per mode. --- src/simu5g/common/LteCommon.h | 9 ++- src/simu5g/common/LteCommonEnum.msg | 2 +- .../LteFeedbackComputationRealistic.cc | 4 +- tests/unit/TxModeCount.test | 81 +++++++++++++++++++ 4 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 tests/unit/TxModeCount.test diff --git a/src/simu5g/common/LteCommon.h b/src/simu5g/common/LteCommon.h index d97cc3301c..4aea7a8d82 100644 --- a/src/simu5g/common/LteCommon.h +++ b/src/simu5g/common/LteCommon.h @@ -210,11 +210,12 @@ typedef unsigned short NumerologyIndex; * Transmission Modes * *************************/ -/// Number of transmission modes in DL direction. -const unsigned char DL_NUM_TXMODE = 6; //UNKNOWN_TX_MODE; +/// Number of transmission modes in DL direction: the TxMode enumerators before the UNKNOWN_TX_MODE sentinel. +/// Feedback vectors and the AMC's feedback histories hold one entry per mode, indexed by TxMode. +const unsigned char DL_NUM_TXMODE = UNKNOWN_TX_MODE; -/// Number of transmission modes in UL direction. -const unsigned char UL_NUM_TXMODE = 6; //UNKNOWN_TX_MODE; +/// Number of transmission modes in UL direction (see DL_NUM_TXMODE). +const unsigned char UL_NUM_TXMODE = UNKNOWN_TX_MODE; typedef std::map TxModeMap; diff --git a/src/simu5g/common/LteCommonEnum.msg b/src/simu5g/common/LteCommonEnum.msg index 794f8c5757..5c298e3522 100644 --- a/src/simu5g/common/LteCommonEnum.msg +++ b/src/simu5g/common/LteCommonEnum.msg @@ -129,7 +129,7 @@ enum PilotComputationModes /// Transmission Modes enum TxMode { - // Note: If you add more tx modes, update DL_NUM_TXMODE and UL_NUM_TXMODE + // Note: UNKNOWN_TX_MODE stays last; DL_NUM_TXMODE and UL_NUM_TXMODE (LteCommon.h) take their value from it SINGLE_ANTENNA_PORT0 = 0; TRANSMIT_DIVERSITY = 1; UNKNOWN_TX_MODE = 2; diff --git a/src/simu5g/stack/phy/feedback/LteFeedbackComputationRealistic.cc b/src/simu5g/stack/phy/feedback/LteFeedbackComputationRealistic.cc index 1395f85016..effe1e4043 100644 --- a/src/simu5g/stack/phy/feedback/LteFeedbackComputationRealistic.cc +++ b/src/simu5g/stack/phy/feedback/LteFeedbackComputationRealistic.cc @@ -118,8 +118,8 @@ LteFeedbackDoubleVector LteFeedbackComputationRealistic::computeFeedback(Feedbac // For each Remote for (int j = 0; j < numRus; j++) { LteFeedback fb; - // For each txmode we generate a feedback excluding MU_MIMO because it is treated as SISO - for (int z = 0; z < DL_NUM_TXMODE - 1; z++) { + // For each txmode we generate a feedback + for (int z = 0; z < DL_NUM_TXMODE; z++) { fb.reset(); fb.setTxMode((TxMode)z); unsigned int rank = 1; diff --git a/tests/unit/TxModeCount.test b/tests/unit/TxModeCount.test new file mode 100644 index 0000000000..08809c216e --- /dev/null +++ b/tests/unit/TxModeCount.test @@ -0,0 +1,81 @@ +%description: + +The transmission-mode count constants against the TxMode enum they count. + +The MIMO transmission modes were removed and TxMode shrank to two modes plus +the UNKNOWN_TX_MODE sentinel, but DL_NUM_TXMODE and UL_NUM_TXMODE stayed at +the old value 6. The feedback computation sizes its per-mode vectors with +DL_NUM_TXMODE and stores (TxMode)z for every index, so it writes the values +3, 4 and 5 into a TxMode: outside the enum's representable range, which the +C++ standard leaves undefined (UBSan: "load of value 4, which is not a valid +value for type 'TxMode'", from LteFeedback::setTxMode and +LteFeedback::isEmptyFeedback on the plant example of factorysim). The AMC +allocates and iterates one feedback history buffer per counted mode, so the +stale count also costs memory and time for modes that no longer exist. + +The checks: the two constants equal the number of real modes (the sentinel's +value), and every feedback the realistic computation returns carries a valid +TxMode, with one entry per real mode. + +%includes: +#include "SchedulerTestUtil.h" +#include "simu5g/common/LteCommon.h" +#include "simu5g/common/binder/Binder.h" +#include "simu5g/stack/phy/feedback/LteFeedback.h" +#include "simu5g/stack/phy/feedback/LteFeedbackComputationRealistic.h" + +%global: +using namespace simu5g; +using namespace simu5g::unittest; + +static bool validTxMode(TxMode m) +{ + int v = static_cast(m); + return v >= SINGLE_ANTENNA_PORT0 && v <= UNKNOWN_TX_MODE; +} + +%activity: +Checker c; + +c.expectValue("DL_NUM_TXMODE counts the modes of the TxMode enum", DL_NUM_TXMODE, UNKNOWN_TX_MODE); +c.expectValue("UL_NUM_TXMODE counts the modes of the TxMode enum", UL_NUM_TXMODE, UNKNOWN_TX_MODE); + +{ + // The feedback computation needs a Binder only to reach its PhyPisaData. + Binder *binder = new Binder(); + LteFeedbackComputationRealistic fbc(binder, 0.01, 1); + std::map antennaCws; + antennaCws[MACRO] = 1; + std::vector snr(1, 20.0); + + // one feedback per remote and transmission mode (the eNB counts as one remote) + LteFeedbackDoubleVector fbvv = fbc.computeFeedback(ALLBANDS, TYPE2_DISTRIBUTED, SINGLE_ANTENNA_PORT0, antennaCws, 1, 0, snr, MacNodeId(1025)); + c.expectValue("one remote: the eNB", fbvv.size(), 1); + c.expectValue("one feedback entry per real transmission mode", fbvv[0].size(), UNKNOWN_TX_MODE); + bool allValid = true, modesSeen[UNKNOWN_TX_MODE] = {}; + for (const LteFeedback& fb : fbvv[0]) { + if (!validTxMode(fb.getTxMode())) + allValid = false; + else if (fb.getTxMode() != UNKNOWN_TX_MODE) + modesSeen[fb.getTxMode()] = true; + } + c.check("every stored TxMode is an enumerator", allValid); + c.check("both real modes get a feedback", modesSeen[SINGLE_ANTENNA_PORT0] && modesSeen[TRANSMIT_DIVERSITY]); + + // the per-remote variant + LteFeedbackVector fbv = fbc.computeFeedback(MACRO, ALLBANDS, TYPE2_DISTRIBUTED, SINGLE_ANTENNA_PORT0, 1, 1, 0, snr, MacNodeId(1025)); + c.expectValue("per-remote variant: one entry per real transmission mode", fbv.size(), UNKNOWN_TX_MODE); + allValid = true; + for (const LteFeedback& fb : fbv) + if (!validTxMode(fb.getTxMode())) + allValid = false; + c.check("per-remote variant: every stored TxMode is an enumerator", allValid); + delete binder; +} +c.summary(); + +%contains: stdout +modelchecks=8 modelfailures=0 + +%not-contains: stdout +FAILED