Repository navigation
Conversation
added 3 commits
November 7, 2026 03:11
…on of flat transmissions Add the IFlatTransmission interface, which returns the length and the modulation of the header and of the data part of a transmission (b(-1) for an unknown length, nullptr for an unknown modulation), and IModulation::getBitsPerSymbol(), which returns the number of coded bits that a symbol carries (0, the default, if unknown). IFlatTransmission is implemented by ApskTransmission and Ieee802154Transmission (from the lengths and the modulation they already store; the lengths of UWB-IR transmissions are b(-1)) and by Ieee80211Transmission. The latter has no bit model for scalar and dimensional signals, so it computes the lengths from the mode and the PHY header, the way Ieee80211ErrorModelBase::computePacketErrorRate does. getBitsPerSymbol() is implemented by ApskModulationBase (code word size), DpskModulationBase (log2 of the constellation size) and Ieee80211OfdmModulation (the subcarrier modulation). This is groundwork for deriving the missing error rates in StochasticErrorModel (#1429) without common/ depending on technology packages. No behavior change.
…ives the missing error rates consistently (#1429) StochasticErrorModel::initialize() did not call ErrorModelBase::initialize(), so corruptionMode, snirMode and snirOffset were never read and the first lost frame ended the run with "Unknown corruption mode". computeBitErrorRate() threw "Not yet implemented" unless bitErrorRate was set, although FlatReceiverBase asks for the packet, bit and symbol error rate of every reception. computePacketErrorRate() dereferenced the bit model, which is null for scalar and dimensional IEEE 802.11 transmissions, and estimated the header share of the packet error rate from the signal durations. The three rates are now consistent under the assumption of independent errors: PER = 1 - (1 - BER)^L over the L bits of the packet (or of its header or data part), and SER = 1 - (1 - BER)^k with k bits per symbol. A rate that is set is returned as is; otherwise it is derived: the packet error rate from the bit error rate, the bit error rate from the symbol error rate (if the modulation has bits per symbol) or else from the packet error rate over the whole packet, and the symbol error rate from the bit error rate. A rate that cannot be derived is NaN, which ErrorRateInd allows. The packet error rate of the whole packet is composed from those of the header and the data part (each with its own modulation), as the other error models do. The lengths and modulations come from IFlatTransmission, then from the bit model, then the whole packet is data. A negative length is unknown. If symbolErrorRate is the only parameter set and the modulation of a part has no bits per symbol (CCK of IEEE 802.11b, FHSS, PPM, FSK), the run stops with an error that names the part and the transmission. The coding rate is ignored in the symbol/bit relation; the NED documentation says so. The parameters are checked to be NaN or in [0, 1]. Tests: tests/module/StochasticErrorModel_{1..17}.test, with the network, the verdict script and a probe error model (which also records the header and data rates) in tests/module/lib.
…ing error rate instead of looping or deciding on NaN
ErrorModelBase::computeCorruptedPacket(const ISnir *) passed the bit error
rate of the error model to the corruption modes chunk, byte and bit without
looking at it. With a bit error rate of 0 no chunk, byte or bit is ever
corrupted, so the loop that corrupts a packet whose reception has already
failed ran forever. With a NaN bit error rate the ASSERT in
hasProbabilisticError() failed in a debug build, and a release build looped
forever as well. Now the bit error rate is only requested for the corruption
modes that use it, and a NaN or non-positive value stops the run with an error
that names the error model and the corruption mode.
FlatReceiverBase::computeIsReceptionSuccessful() compared a NaN packet error
rate with 0 and 1 and then asserted on it (debug), or lost the reception
silently, because dblrand() > NaN is false (release). It now stops the run
with an error that names the error model.
An error model that never called ErrorModelBase::initialize() (corruptionMode stays
undefined, as in StochasticErrorModel before the previous commit) now fails with
an error that names the missing call instead of the misleading message about
corruptionMode = "packet" (or, before, "Unknown corruption mode").
Behavior change for all error models: a run that used to loop forever, fail
an assertion or lose every frame silently now ends with an error. Packet error
rates that are numbers, and corruptionMode = "packet", are not affected. The
error models of IEEE 802.11 (Nist, Yans, BerTable) return no bit error rate,
so that corruptionMode chunk, byte or bit with them now fails with the new
message at the first lost frame instead of with "Unimplemented corruption
mode" from Ieee80211ErrorModelBase.
Tests: tests/module/StochasticErrorModel_{18..24}.test, with the helper error
model ConstantRatesErrorModel in tests/module/lib.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1429. On master 7ec0d4d, three commits.
Problem
StochasticErrorModelcould not be used in an IEEE 802.11 network (details and reproduction in #1429):initialize()did not callErrorModelBase::initialize(), socorruptionModestayed undefined and the first lost frame ended the run withUnknown corruption mode.computeBitErrorRate()threwNot yet implementedunlessbitErrorRatewas set, althoughFlatReceiverBaseasks for the packet, bit and symbol error rate of every reception.computePacketErrorRate()dereferenced the bit model, which is null for scalar and dimensional 802.11 transmissions (segmentation fault).The three commits, and why they are separate
physicallayer: add: accessors for the header/data length and modulation of flat transmissionsAdds
IFlatTransmission(header length, data length, header modulation, data modulation;b(-1)is an unknown length,nullptran unknown modulation) andIModulation::getBitsPerSymbol()(default 0 = unknown). Implemented byApskTransmission,Ieee802154TransmissionandIeee80211Transmission, and byApskModulationBase,DpskModulationBaseandIeee80211OfdmModulation.Ieee80211Transmissioncomputes the lengths from the mode and the PHY header, the wayIeee80211ErrorModelBase::computePacketErrorRatedoes. No behavior change. It is a contract change, so it stands alone. It lets the fix in commit 2 use one interface cast instead of casts to technology classes, socommon/does not depend onieee80211/,apsk/orieee802154/, and radios outside the tree can implement the interface.physicallayer: fix: StochasticErrorModel initializes the base and derives the missing error rates consistently (#1429)The fix itself, with the NED documentation and the tests.
physicallayer: fix: ErrorModelBase and FlatReceiverBase report a missing error rate instead of looping or deciding on NaNGuards in two base classes. They change behavior for every error model, so they are separate from the model fix and have their own tests. The
ber == 0infinite loop is named in the commit body.Each commit builds, and the whole
tests/modulesuite gives the same results after commits 1, 2 and 3 as before, plus the new tests.Design of the fix (commit 2)
Under the assumption of independent errors, with
Lthe length of the packet (or of its header or data part) in bits andkthe bits per symbol of the modulation:(computed with
expm1/log1p). Eachcompute*ErrorRate()returns its own parameter if it is set, otherwise it derives the value:packetErrorRateif set. Otherwise composed from the parts:1 - (1 - PER_header) * (1 - PER_data), in log spacepacketErrorRateis set, the share1 - (1 - PER)^(L_part / L_whole). OtherwisePER_part = 1 - (1 - BER_part)^L_part, whereBER_partuses the modulation of that part. PREAMBLE is 0bitErrorRateif set; else fromsymbolErrorRateif it is set and the modulation of the part has bits per symbol; else frompacketErrorRateover the whole packet (header + data)symbolErrorRateif set; else from the bit error rate with the bits per symbol of the partPrecedence when several parameters are set: a rate that is set is returned as is. A rate that is not set is derived from the bit error rate if set, else from the symbol error rate, else from the packet error rate (bit error rate over symbol error rate over packet error rate). A rate that cannot be derived is NaN, which
ErrorRateIndallows.Where the header and data lengths and modulations come from:
IFlatTransmission(onedynamic_cast), else the bit model if the transmission has one, else the whole packet is data with no modulation. A negative length counts as unknown, in one place (getPartLengths).UWB-IRtransmissions are the case that hasb(-1)lengths, but the UWB-IR receiver is aReceiverBase, not aFlatReceiverBase, so it cannot use an error model; that path is not reachable in a simulation and is not tested.If only
symbolErrorRateis set and the modulation of a part has no bits per symbol (CCK of 802.11b/g at 5.5 and 11 Mbit/s, FHSS, IR, and the FSK/PPM/MFSK modulations in general), the run stops at the first reception with an error that names the part, the transmission class and the modulation class (the CCK data mode has no modulation object, so the message saysmodulation not specifiedfor it). Other combinations return NaN for the rates that cannot be derived.The parameters are checked to be NaN (unset) or in [0, 1] in
initialize().Approximations (documented in the NED file)
kis the number of coded bits that a constellation symbol carries, whileLis the length of the packet after decoding (PSDU plus tail and padding bits for 802.11 OFDM). At 24 Mbit/s (16-QAM, rate 1/2) a symbol carries 4 coded and 2 data bits. The symbol error rate is therefore not the symbol error rate of the decoded packet.Ieee80211OfdmModulation::getBitsPerSymbol()returns the bits of the subcarrier modulation).ErrorRateInd, use the modulation of the data part.Behavior changes of commit 3, for all error models
FlatReceiverBase::computeIsReceptionSuccessful(): a NaN packet error rate stops the run withError model <class> cannot provide the packet error rate that the reception decision requires. Before, a debug build failed anASSERTand a release build lost the frame silently (dblrand() > NaNis false). This applies to every error model that can return NaN there.ErrorModelBase::computeCorruptedPacket(const ISnir *):computeBitErrorRate()is only called for the corruption modeschunk,byteandbit(it was called forpacket, where the value was unused).Error model <class> cannot provide a bit error rate for corruptionMode = "<mode>"; use corruptionMode = "packet" or an error model that computes a bit error rate. Before, a debug build failed anASSERTand a release build looped forever.Error model <class> lost a packet but returned a bit error rate of 0, with which corruptionMode = "<mode>" cannot corrupt it. Before,computeCorruptedPacket(packet, ber)looped forever becausehasProbabilisticError()never returns true forber == 0.Ieee80211Nist,Yans,BerTable) return no bit error rate, socorruptionModechunk,byteorbitwith them now fails with this message instead ofUnimplemented corruption modefromIeee80211ErrorModelBase. It was an error before as well.ErrorModelBase::initialize()(corruptionModestays undefined, as inStochasticErrorModelbefore this fix) fails withError model <class> did not initialize its corruption mode, its initialize() must call ErrorModelBase::initialize(). Before, it ended withUnknown corruption modefrom the corruption loop. This is checked first, so the other messages never mention a corruption mode that was not set.Ieee80211BerTableErrorModelis such a model; fixing it is not part of this PR.corruptionMode = "packet"and finite packet error rates are not affected; no reception decision changes.The messages name the class of the error model and the corruption mode and no parameter, since the check runs for every error model.
Tests
tests/module/libgotStochasticErrorModelTest.ned(network),stochastic-errormodel*.ini(one common file and one per technology: IEEE 802.11, APSK, IEEE 802.15.4),stochastic-errormodel.awk(verdict),StochasticErrorModelProbe(aStochasticErrorModelthat records the smallest and largest value returned for each rate and part, and computes the HEADER and DATA rates on every request, which the receivers do not ask for) and, in commit 3,ConstantRatesErrorModel. Each test is a.testfile with its parameters and anincludeof the technology file, as the existingIeee8021adPolicyInvalid_*tests do. The expected values are computed by an independent implementation of the closure, not by the C++ code. The frame counts use 4 sigma of the binomial with n = 500 (a miss probability of about 6e-5 for a correct model, deterministic seeds); rates are compared to a relative precision of 1e-6.packetErrorRate = 0.3(packet mode)corruptionMode = "chunk"bitErrorRateonlysymbolErrorRateonly: BPSK header, 16-QAM data, WHOLE composed from the partssymbolErrorRateonly, dimensional analog modelpacketErrorRate = 1, chunk: BER 1, all frames lostbitErrorRate = 0, chunk: nothing lost, nothing to corruptpacketErrorRateonly: SER of the data is NaNsymbolErrorRateonly: error naming the modulationsymbolErrorRate,packetErrorRatesymbolErrorRate,packetErrorRateApskLayeredTransmitter(transmissions with a bit model) and the packet level receiverFlatReceiverBaseIeee80211NistErrorModelwithchunk: NaN bit error rateber == 0loop)chunkcorruptionMode = "packet"needs no bit error rate (passes before and after, by design)StochasticErrorModelwith no rate setErrorModelBase::initialize()(corruption mode undefined)Verification
Run on macOS (Apple clang, OMNeT++ 6.5.0,
-j8, ccache), release (MODE=release) and debug (MODE=debug) builds.tests/module, release and debug, the whole directory (826.testfiles on master, built the way the removedtests/module/runtestdid:libcopied into a work directory, one executable for all tests,opp_test runin four parallel shards):The per-test result lists differ between master and the final head only by the 24 added tests, which all pass. The failures on master are not touched by this change. I did not analyze each of them. The ones I looked at: four tests whose own C++ sources do not compile with this toolchain (
Ieee80211BlockAckDeferral_1,Ieee80211BlockAckDeferredCollision_1,Ieee80211EdcaDataLifetimeArbitration_1,Ieee80211MgmtApHcfRtsTimeout_1; they are left out of the test executable and fail the same way before and after),ExternalProcess_*(External processes are only supported on Linux), and in release builds a large group whose expected output does not match (e.g.tcp_*,IPv6_*); in debug builds the IPv6/MLD tests,LogNormalShadowing_Correlated_*and others fail on master too.Ieee80211BitDomain(andIeee80211SymbolDomain,ConvolutionalCoder12,ConvolutionalCoder34) use the C++ test library intests/module/lib. They pass in the debug run and fail in the release run, identically on master and on commit 3. I built them with the library and checked the results; they fail in release on master as well.tests/unit, release and debug (148.testfiles; 7 sources that do not compile are left out): same results on master and on commit 3 in both modes (release 125 pass, debug 134 pass).examples/wireless/corruptionmode, all four configurations (PacketCorruptionMode,ChunkCorruptionMode,ByteCorruptionMode,BitCorruptionMode), release and debug, run 0: the result files (about 2100 scalar lines each) are identical on master, after commit 1 and after commit 3, in both modes.Fingerprints. This INET keeps the fingerprints in
tests/fingerprint/store.json(there are no CSV files, and theopp_replrunner was not installed here), so I wrote a small runner that runs the same entries (inet -u Cmdenv -f <ini> -c <config> -r <run> --sim-time-limit=<t> --fingerprint=0000-0000/<ingredients>,--fingerprintcalculator-class=inet::FingerprintCalculatorfor~ingredients, computed checksum/FCS modes for~tND) and records the calculated value. 1197 entries from the wireless-related directories (examples/wireless/*,examples/adhoc/ieee80211,idealwireless,ieee8021as,showcases/wireless/*,tutorials/wireless,showcases/visualizer/canvas/ieee80211; ingredientstplx410,~tNl410,~tND377;tyfis graphical and was skipped), release build only: master, commit 1 and commit 3 give the identical calculated fingerprint for all 1197 entries. Against the stored values, 409 of 410tplx, 409 of 410~tNland 374 of 377~tNDmatch, on all three revisions. The 5 that do not match are the same before and after:showcases/wireless/sensornetworkStatisticLMac(stored0000-0000; the run stops withI am still sending a message, while a new slot is starting!) fortplxand~tNl, and threeexamples/ieee8021as~tNDentries. This includes every 802.11 example with the defaultIeee80211NistErrorModel, which returns a NaN bit error rate, in packet mode. Fingerprints after commit 2 were not run (commit 2 is covered by thetests/modulesuite), and fingerprints were not run in a debug build.Each new test fails without the change. Run on master (
7ec0d4d3f3with the test files of this branch added); a hang was stopped after 150 s:Not yet implementedUnknown corruption modeNot yet implemented(expected message missing)Not yet implemented(no range check)ASSERTinFlatReceiverBaseASSERTinFlatReceiverBaseUnimplemented corruption modeASSERTinhasProbabilisticErrorNot yet implementedUnknown corruption modeTests 18-24 also fail on commit 2 alone (release: 18 exit 0, 19 message, 20 and 21 loop, 23 exit 0, 24
Unknown corruption mode; debug: all message/assertion), so they test commit 3. All 24 pass on the final head, in both modes.Not run: the
tests/misc/ns3validation tests (they need ns-3, and theirNs3Test.neddoes not parse on this tree).tests/misc/ns3/lib/ns3test.inisetsbitErrorRate = 0on the 802.11a scalar radio. On master that configuration crashes incomputePacketErrorRate(the null bit model; test 9 reproduces it on 802.11g). With the fix the same setting runs and loses no frame (test 9, on 802.11g); I did not run the ns-3 scenario itself. Also not run: the other fingerprint directories,tests/packet,tests/protocol,tests/validationand the showcases beyond their fingerprints.Notes on the evidence. The table of failures on master was assembled from two runs: all tests on master, then tests 18, 21 and 23 again after their final form (they were reworked once). The
tests/moduleand fingerprint runs for master~tNDrows were done twice (the first attempt lacked the computed checksum modes), only the second was compared. Of the transmissions in the tree that carry a bit model, all also implementIFlatTransmissionwith known lengths, so test 17 takes the interface branch; the bit-model and "whole packet is data" fallbacks inStochasticErrorModelare not exercised by a test (generic transmissions have no error model). No ChangeLog entry is added for the behavior change of commit 3 (INET fillssrc/ChangeLogat release). Not part of this PR:Ieee80211BerTableErrorModel::initialize()has the same missingErrorModelBase::initialize()call that caused #1429.Final head. After the last change (the undefined-corruption-mode check and test 24) I re-ran on the final head, release and debug: tests 18-24 (all pass), the whole
tests/modulesuite (850 tests; release 468 pass / 379 fail / 3 error, debug 796 / 52 / 2; the result lists differ from master only by the 24 added tests, all PASS) and the fourcorruptionmodeconfigurations (scalars identical to master in both modes). The numbers for commits 1 and 2,tests/unitand the fingerprints were measured on the earlier heads of this branch; the source of the final head differs from those only by the commit 3 check above, a NED comment sentence and test 10's description, and fingerprints were not repeated on the final head.