Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions WHATSNEW
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,49 @@ Notable backward incompatible changes are the following:
This change requires the modification of C++ code that implements
IRadioMedium without deriving from RadioMedium.

23. The distance form of the path loss is computeDistancePathLoss()

IPathLoss::computePathLoss(propagationSpeed, frequency, distance) was
renamed to computeDistancePathLoss(), so that it is no longer an overload
of the method that computes the path loss of a reception (see the next
item): a model that overrode one of the overloads hid the other. Its
documentation now states that the value is independent of the transmitter
and the receiver, and may be NaN when the model cannot tell the loss from
the distance alone (TwoRayInterference).

This change requires the modification of C++ code that implements or calls
computePathLoss(propagationSpeed, frequency, distance): every path loss
model derived from PathLossBase overrides it.

24. The path loss of a reception knows its receiver

IPathLoss::computePathLoss(transmission, arrival) was replaced by
computeReceptionPathLoss(receiverRadio, transmission, arrival). It returns
an IReceptionPathLoss, the path loss of that one reception, whose
computePathLoss(frequency) gives the loss factor at any frequency, the way
IAntenna::getGain() returns an IAntennaGain. Together with the
transmission's transmitter radio, the receiver radio identifies the link,
so a path loss can now keep per-link state (for example a shadowing that
is correlated over distance). Both medium analog models call it once per
reception: ScalarMediumAnalogModel evaluates the result at the center
frequency, DimensionalMediumAnalogModel across the band, in place of the
computeDistancePathLoss() it called before. A path loss with per-link
state resolves that state in the call, and the returned object holds
values only, so the value of a reception does not depend on when or how
often the dimensional model evaluates it. The PathLossBase default
evaluates computeDistancePathLoss() for the link's distance, so the
results of models that only implement that form are unchanged. The
FrequencyDependentAttenuationFunction constructor takes the reception's
path loss as its second argument.

TwoRayGroundReflection and TwoRayInterference now take the geometry of the
link into account under DimensionalMediumAnalogModel too: before, the
former acted as FreeSpacePathLoss there, and the latter returned NaN.

This change requires the modification of C++ code that implements or calls
computePathLoss(transmission, arrival), or constructs
FrequencyDependentAttenuationFunction objects.

Notable backward compatible changes are the following:

1. IEEE 802.11 per-station rate statistics
Expand Down Expand Up @@ -508,6 +551,28 @@ Notable backward compatible changes are the following:
reservation time, and support limits. The feature does not implement full
shared TXNAV or admission of a complete exchange against the remaining budget.

9. Correlated log-normal shadowing

LogNormalShadowing has a new correlationDistance parameter. By default
(NaN) every path loss computation draws a new shadowing value, as before.
With a distance, the value is kept per pair of radios, the same in both
directions, and drawn again only when either radio has moved farther than
that distance from where it was when the value was drawn, which is how
shadowing behaves physically. The value is resolved once per reception,
so with DimensionalMediumAnalogModel the whole band of a reception has
the same shadowing. The values of a radio's links are dropped when the
radio is removed from the medium.

10. Log-normal shadowing once per reception

Without a correlation distance, LogNormalShadowing draws one shadowing
value per reception. With DimensionalMediumAnalogModel it drew one per
evaluation of the attenuation, so the frequencies of one reception had
independent values, and an evaluation repeated later gave a different
one. With ScalarMediumAnalogModel, or with the dimensional model
attenuating with the center frequency (the default), nothing changes.


INET-4.7 (July 2026) — feature release
--------------------------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ const Ptr<const IFunction<WpHz, Domain<simsec, Hz>>> DimensionalMediumAnalogMode
EV_TRACE << "Transmission power end" << endl;
Point<simsec, Hz> propagationShift(simsec(arrival->getStartTime() - transmission->getStartTime()), Hz(0));
const auto& propagatedTransmissionPowerFunction = makeShared<DomainShiftedFunction<WpHz, Domain<simsec, Hz>>>(transmissionPowerFunction, propagationShift);
Ptr<const IFunction<double, Domain<simsec, Hz>>> attenuationFunction = makeShared<FrequencyDependentAttenuationFunction>(radioMedium, transmitterAntennaGain, receiverAntennaGain, transmissionStartPosition, receptionStartPosition);
const auto& receptionPathLoss = radioMedium->getPathLoss()->computeReceptionPathLoss(receiverRadio, transmission, arrival);
Ptr<const IFunction<double, Domain<simsec, Hz>>> attenuationFunction = makeShared<FrequencyDependentAttenuationFunction>(radioMedium, receptionPathLoss, transmitterAntennaGain, receiverAntennaGain, transmissionStartPosition, receptionStartPosition);
Ptr<const IFunction<WpHz, Domain<simsec, Hz>>> receptionPower;
if (attenuateWithCenterFrequency) {
const auto& constantAttenuationFunction = makeShared<ConstantFunction<double, Domain<simsec, Hz>>>(attenuationFunction->getValue(Point<simsec, Hz>(simsec(0), analogModel->getCenterFrequency())));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ W ScalarMediumAnalogModel::computeReceptionPower(const IRadio *receiverRadio, co
// TODO could be used for doppler shift? const Coord& receptionEndPosition = arrival->getEndPosition();
double transmitterAntennaGain = computeAntennaGain(transmission->getTransmitterAntennaGain(), transmission->getStartPosition(), arrival->getStartPosition(), transmission->getStartOrientation());
double receiverAntennaGain = computeAntennaGain(receiverRadio->getAntenna()->getGain().get(), arrival->getStartPosition(), transmission->getStartPosition(), arrival->getStartOrientation());
double pathLoss = radioMedium->getPathLoss()->computePathLoss(transmission, arrival);
double pathLoss = radioMedium->getPathLoss()->computeReceptionPathLoss(receiverRadio, transmission, arrival)->computePathLoss(analogModel->getCenterFrequency());
double obstacleLoss = radioMedium->getObstacleLoss() ? radioMedium->getObstacleLoss()->computeObstacleLoss(analogModel->getCenterFrequency(), transmission->getStartPosition(), receptionStartPosition) : 1;
W transmissionPower = analogModel->getPower();
ASSERT(!std::isnan(transmissionPower.get()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@
#include "inet/physicallayer/wireless/common/base/packetlevel/PathLossBase.h"

#include "inet/physicallayer/wireless/common/contract/packetlevel/IRadioMedium.h"
#include "inet/physicallayer/wireless/common/contract/packetlevel/IRadioSignal.h"

#include "inet/physicallayer/wireless/common/analogmodel/scalar/ScalarTransmitterAnalogModel.h"

namespace inet {

namespace physicallayer {

double PathLossBase::computePathLoss(const ITransmission *transmission, const IArrival *arrival) const
std::ostream& PathLossBase::DistanceReceptionPathLoss::printToStream(std::ostream& stream, int level, int evFlags) const
{
stream << "DistanceReceptionPathLoss";
if (level <= PRINT_LEVEL_DEBUG)
stream << EV_FIELD(distance);
if (level <= PRINT_LEVEL_TRACE)
stream << EV_FIELD(propagationSpeed) << EV_FIELD(pathLoss, printFieldToString(pathLoss, level + 1, evFlags));
return stream;
}

Ptr<const IReceptionPathLoss> PathLossBase::computeReceptionPathLoss(const IRadio *receiverRadio, const ITransmission *transmission, const IArrival *arrival) const
{
auto radioMedium = transmission->getMedium();
auto analogModel = check_and_cast<const INarrowbandSignalAnalogModel *>(transmission->getAnalogModel());
mps propagationSpeed = radioMedium->getPropagation()->getPropagationSpeed();
Hz centerFrequency = Hz(analogModel->getCenterFrequency());
mps propagationSpeed = transmission->getMedium()->getPropagation()->getPropagationSpeed();
m distance = m(arrival->getStartPosition().distance(transmission->getStartPosition()));
return computePathLoss(propagationSpeed, centerFrequency, distance);
return makeShared<DistanceReceptionPathLoss>(this, propagationSpeed, distance);
}

} // namespace physicallayer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,26 @@ namespace physicallayer {

class INET_API PathLossBase : public Module, public IPathLoss
{
protected:
/**
* The path loss of a reception reduced to its distance: computed by
* computeDistancePathLoss() at each frequency.
*/
class INET_API DistanceReceptionPathLoss : public IReceptionPathLoss {
protected:
const PathLossBase *pathLoss;
mps propagationSpeed;
m distance;

public:
DistanceReceptionPathLoss(const PathLossBase *pathLoss, mps propagationSpeed, m distance) : pathLoss(pathLoss), propagationSpeed(propagationSpeed), distance(distance) {}
virtual double computePathLoss(Hz frequency) const override { return pathLoss->computeDistancePathLoss(propagationSpeed, frequency, distance); }
virtual std::ostream& printToStream(std::ostream& stream, int level, int evFlags = 0) const override;
};

public:
virtual double computePathLoss(mps propagationSpeed, Hz frequency, m distance) const override = 0;
virtual double computePathLoss(const ITransmission *transmission, const IArrival *arrival) const override;
virtual double computeDistancePathLoss(mps propagationSpeed, Hz frequency, m distance) const override = 0;
virtual Ptr<const IReceptionPathLoss> computeReceptionPathLoss(const IRadio *receiverRadio, const ITransmission *transmission, const IArrival *arrival) const override;
};

} // namespace physicallayer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
#define __INET_IPATHLOSS_H

#include "inet/physicallayer/wireless/common/contract/packetlevel/IArrival.h"
#include "inet/physicallayer/wireless/common/contract/packetlevel/IReceptionPathLoss.h"
#include "inet/physicallayer/wireless/common/contract/packetlevel/ITransmission.h"

namespace inet {

namespace physicallayer {

class IRadio;

/**
* This interface models path loss (or path attenuation) that is the reduction
* in power density of a radio signal as it propagates through space.
Expand All @@ -23,18 +26,25 @@ class INET_API IPathLoss : public virtual IPrintableObject
{
public:
/**
* Returns the loss factor for the provided transmission and arrival.
* The value is in the range [0, 1] where 1 means no loss at all and 0
* means all power is lost.
* Returns the path loss of the reception of the provided transmission by
* the provided receiver radio, for the provided arrival. The medium
* analog model calls this once per reception, when it computes the
* reception, and evaluates the result at one or more frequencies, at that
* time or later. A model that keeps per-link state resolves it in this
* call. The returned object may refer to the path loss model, but not to
* the transmission, the arrival or the radios: the medium may delete them
* while the reception's power is still evaluated.
*/
virtual double computePathLoss(const ITransmission *transmission, const IArrival *arrival) const = 0;
virtual Ptr<const IReceptionPathLoss> computeReceptionPathLoss(const IRadio *receiverRadio, const ITransmission *transmission, const IArrival *arrival) const = 0;

/**
* Returns the loss factor as a function of propagation speed, carrier
* frequency and distance. The value is in the range [0, 1] where 1 means
* no loss at all and 0 means all power is lost.
* frequency and distance, independently of the transmitter and the
* receiver. The value is in the range [0, 1] where 1 means no loss at all
* and 0 means all power is lost, or NaN if the model cannot tell the loss
* from the distance alone.
*/
virtual double computePathLoss(mps propagationSpeed, Hz frequency, m distance) const = 0;
virtual double computeDistancePathLoss(mps propagationSpeed, Hz frequency, m distance) const = 0;

/**
* Returns the range for the given loss factor. The value is in the range
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// Copyright (C) 2026 OpenSim Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//


#ifndef __INET_IRECEPTIONPATHLOSS_H
#define __INET_IRECEPTIONPATHLOSS_H

#include "inet/common/IPrintableObject.h"
#include "inet/common/Ptr.h"
#include "inet/common/Units.h"

namespace inet {
namespace physicallayer {

using namespace inet::units::values;

/**
* This interface represents the path loss of one reception, that is between
* one transmission and one receiver, over frequency. It is created by
* IPathLoss::computeReceptionPathLoss() when the reception is computed, and
* it may be evaluated at any later time, any number of times.
*/
class INET_API IReceptionPathLoss : public virtual IPrintableObject
#if INET_PTR_IMPLEMENTATION == INET_INTRUSIVE_PTR
, public IntrusivePtrCounter<IReceptionPathLoss>
#endif
{
public:
/**
* Returns the loss factor at the given frequency. The value is in the
* range [0, 1] where 1 means no loss at all and 0 means all power is
* lost. For the same frequency the value is the same, however often and
* however late it is asked for.
*/
virtual double computePathLoss(Hz frequency) const = 0;
};

} // namespace physicallayer
} // namespace inet

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ std::ostream& BreakpointPathLoss::printToStream(std::ostream& stream, int level,
return stream;
}

double BreakpointPathLoss::computePathLoss(mps propagationSpeed, Hz frequency, m distance) const
double BreakpointPathLoss::computeDistancePathLoss(mps propagationSpeed, Hz frequency, m distance) const
{
// PL(d) = PL0 + 10 alpha log10 (d/d0)
// 10 ^ { PL(d)/10 } = 10 ^{PL0 + 10 alpha log10 (d/d0)}/10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class INET_API BreakpointPathLoss : public PathLossBase
public:
BreakpointPathLoss();
virtual std::ostream& printToStream(std::ostream& stream, int level, int evFlags = 0) const override;
virtual double computePathLoss(mps propagationSpeed, Hz frequency, m distance) const override;
virtual double computeDistancePathLoss(mps propagationSpeed, Hz frequency, m distance) const override;
virtual m computeRange(mps propagationSpeed, Hz frequency, double loss) const override;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ double FreeSpacePathLoss::computeFreeSpacePathLoss(m waveLength, m distance, dou
return distance.get() == 0.0 ? 1.0 : (waveLength * waveLength).get() / (16 * M_PI * M_PI * systemLoss * pow(distance.get<m>(), alpha));
}

double FreeSpacePathLoss::computePathLoss(mps propagationSpeed, Hz frequency, m distance) const
double FreeSpacePathLoss::computeDistancePathLoss(mps propagationSpeed, Hz frequency, m distance) const
{
m waveLength = propagationSpeed / frequency;
return computeFreeSpacePathLoss(waveLength, distance, alpha, systemLoss);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class INET_API FreeSpacePathLoss : public PathLossBase
public:
FreeSpacePathLoss();
virtual std::ostream& printToStream(std::ostream& stream, int level, int evFlags = 0) const override;
virtual double computePathLoss(mps propagationSpeed, Hz frequency, m distance) const override;
virtual double computeDistancePathLoss(mps propagationSpeed, Hz frequency, m distance) const override;
virtual m computeRange(mps propagationSpeed, Hz frequency, double loss) const override;
};

Expand Down
Loading
Loading