Repository navigation
IPathLoss: the path loss of a reception, per receiver and over frequency - #1308
Merged
torokati44 merged 4 commits intoOct 13, 2026
Merged
Conversation
This was referenced Oct 13, 2026
torokati44
force-pushed
the
topic/pathloss-per-receiver
branch
from
October 13, 2026 10:21
cdf0988 to
9173331
Compare
torokati44
marked this pull request as ready for review
October 13, 2026 13:32
IPathLoss had two computePathLoss() overloads: one for a transmission and an arrival, one for a propagation speed, a frequency and a distance. Every path loss model derived from PathLossBase overrides only the latter, and a class that overrides one overload hides the other in its own scope; the next commit replaces the former with a method that computes the path loss of a reception, so the overload set would only grow more confusing. computePathLoss(propagationSpeed, frequency, distance) is renamed to computeDistancePathLoss(), in IPathLoss, PathLossBase, the eleven models and its three callers (PathLossBase, FrequencyDependentAttenuationFunction and the medium visualizer's PathLossFunction). Its documentation states what the models already do: the value is independent of the transmitter and the receiver, or NaN when the model cannot tell it from the distance alone, as TwoRayInterference. API change, stated in WHATSNEW.
IPathLoss::computePathLoss(transmission, arrival) saw the transmitter (through the transmission) but not the receiver, so no path loss could keep per-link state. DimensionalMediumAnalogModel did not call it at all: it reduced the link to its distance and called computeDistancePathLoss() for every frequency it sampled, so a path loss could not use the link's geometry there either. computeReceptionPathLoss(receiverRadio, transmission, arrival) replaces it and returns an IReceptionPathLoss, the path loss of that one reception, whose computePathLoss(frequency) gives the loss factor at any frequency: the same shape as IAntenna::getGain() and IAntennaGain, and like those it keeps the dimensional math out of the contract. Both medium analog models call it once per reception, with the receiver radio they already had: the scalar one evaluates the result at the center frequency, the dimensional one samples it across the band, through FrequencyDependentAttenuationFunction, which takes the reception's path loss in place of calling the path loss model itself. The dimensional model evaluates its attenuation lazily, possibly several times and at any later time, and the medium may delete the transmission and the arrival before the last evaluation, so the returned object holds values only (and may refer to the path loss model): a path loss that keeps per-link state resolves it in the call. The PathLossBase default returns a DistanceReceptionPathLoss, which calls computeDistancePathLoss() for the link's distance whenever it is evaluated, with the same arguments and at the same moments as both analog models did before. TwoRayGroundReflection and TwoRayInterference, the two models that overrode the replaced method, each return a nested ReceptionPathLoss that holds the link's geometry; under the dimensional model they now use it too, where before the former acted as FreeSpacePathLoss and the latter returned NaN. API change, stated in WHATSNEW.
LogNormalShadowing drew a new shadowing value on every path loss computation: two receptions of the same link at the same position could differ by several sigma. With computeReceptionPathLoss() knowing the receiver radio, a path loss can keep per-link state; this is the first to do so. New parameter correlationDistance, default NaN = the memoryless draw as before. With a distance, the value is kept per pair of radios, keyed by the smaller radio id first, together with the position of each radio at the draw, and drawn again when either radio has moved farther than the distance from its position then. Shadowing is caused by the obstacles on the path between the two radios: it is the same in both directions, and it changes when either end moves (with a receiver-only rule, the uplink of a node moving away from a stationary base station would keep its first value forever). The shadowing draw moved into a helper, computeShadowedPathLoss(); in the default mode it is drawn once per computation at the same point as before. The value is resolved in computeReceptionPathLoss(), once per reception, and the returned ReceptionPathLoss holds it, so it does not depend on when or how often the medium analog model evaluates it: with DimensionalMediumAnalogModel the whole band of a reception has the same shadowing, as with the scalar model. The values of a radio's links are dropped when the radio is removed from the medium, so that in a simulation where nodes come and go the map does not grow with every radio that ever existed. When a correlation distance is set, the module subscribes to IRadioMedium::radioRemovedSignal at its parent module, the medium, which emits the signal on itself; the parent is checked to be an IRadioMedium, as the obstacle loss models and MediumLimitCache look up theirs. With the default nothing is subscribed. Tests: LogNormalShadowing_Correlated_1..5 (stationary nodes: one power for all eight receptions, both directions; the default: a new value every time; host2 circling a stationary host1 at constant distance: a new value per ping, reused by its reply, four powers each received in both directions; host2 deleted after two pings: its one pair is dropped; the stationary case on a dimensional medium: one power spectral density for all eight receptions).
Without a correlation distance, computeReceptionPathLoss() returned the PathLossBase default, which calls computeDistancePathLoss() on every evaluation, and that draws a new shadowing value each time. DimensionalMediumAnalogModel evaluates the attenuation per frequency sample and possibly again later, so the samples of one reception had independent shadowing values, and a repeated evaluation gave a different one. computeReceptionPathLoss() now draws the value once, when the reception is computed, and returns a ReceptionPathLoss that holds it, as with a correlation distance. The scalar model and the dimensional one with the default attenuateWithCenterFrequency evaluate it once, right after the call, so the draws happen in the same order as before. computeDistancePathLoss() keeps drawing per call; only callers without a link use it.
torokati44
force-pushed
the
topic/pathloss-per-receiver
branch
from
October 13, 2026 13:40
9173331 to
d83f1ee
Compare
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.
What
IPathLossgets a per-reception method that knows the receiver radio:It replaces
computePathLoss(transmission, arrival). The returnedIReceptionPathLossgives the loss factor at any frequency throughcomputePathLoss(Hz). This is the same shape asIAntenna::getGain()andIAntennaGain.Why
DimensionalMediumAnalogModelnever called the link form. It called the distance form per frequency, so link geometry (the TwoRay models) was ignored there.IFunction) out of the path-loss contract.Commits
computePathLoss(speed, frequency, distance)becomescomputeDistancePathLoss(). It was overloaded with the link form, and overriding one overload hid the other. Mechanical.computeReceptionPathLoss()andIReceptionPathLoss. ThePathLossBasedefault reduces the link to its distance.TwoRayGroundReflectionandTwoRayInterferencekeep the link's geometry. Both analog models call it once per reception.LogNormalShadowinggets an optionalcorrelationDistance; the default, NaN, keeps the old behaviour. With a distance, there is one value per radio pair, the same in both directions, redrawn when either end moves farther than that distance.LogNormalShadowingnow draws one value per reception. Before, under the dimensional model, it drew one per evaluation.Compatibility
Breaking C++ API (WHATSNEW incompatible items 23 and 24):
PathLossBasemust rename itscomputePathLoss(speed, frequency, distance)override;computePathLoss(transmission, arrival), or constructsFrequencyDependentAttenuationFunction, must be updated.No NED or ini changes except the new
correlationDistanceparameter. Default behaviour is unchanged. Under the dimensional model, both TwoRay models now use the link's geometry; before,TwoRayGroundReflectionacted as free space andTwoRayInterferencereturned NaN.Testing
LogNormalShadowing_Correlated_1to_5.Notes for review
computeDistancePathLoss()is now documented as possibly NaN. The medium visualizer's power-density maps don't handle NaN; that is already the case today withTwoRayInterference.