Skip to content

DielectricObstacleLoss: fix: compute the dielectric loss as the power decay of a plane wave - #1438

Open
tabgab wants to merge 1 commit into
inet-framework:masterfrom
tabgab:fix/dielectric-loss-exponent
Open

tabgab wants to merge 1 commit into
inet-framework:masterfrom
tabgab:fix/dielectric-loss-exponent

Conversation

@tabgab

@tabgab tabgab commented Nov 7, 2026

Copy link
Copy Markdown

Fixes #1437. On master 7ec0d4d, one commit.

DielectricObstacleLoss::computeDielectricLoss() returned exp(-2 atan(tan(delta)) k z) as the power factor of an obstacle. The page that it cites gives the power decay of a plane wave as exp(-k z tan(delta)), so every wall took twice as many dB as it should: 3.085 dB instead of 1.542 dB for a 0.2 m concrete wall at 2.4 GHz. The factor is now the exact power decay of a plane wave in a material with the loss tangent tan(delta):

-    double lossTangent = material->getDielectricLossTangent(frequency);
+    double t = material->getDielectricLossTangent(frequency);
     mps propagationSpeed = material->getPropagationSpeed();
-    double delta = atan(lossTangent);
     auto k = 2 * M_PI * frequency / propagationSpeed; // unit is 1/m
     m z = distance;
-    double factor = std::exp(-2 * delta * (k * z).get<unit>());
+    double rootMinusOne = t < 1 ? t * t / (std::sqrt(1 + t * t) + 1) : std::sqrt(1 + t * t) - 1;
+    double alphaZ = std::sqrt(rootMinusOne / 2) * (k * z).get<unit>();
+    double factor = std::exp(-2 * alphaZ);

that is exp(-2 alpha z) with alpha = k sqrt((sqrt(1 + tan²(delta)) - 1) / 2), the attenuation constant of a plane wave in a medium with the complex permittivity eps (1 - j tan(delta)). k stays the wave number of the lossless material (2 pi f / getPropagationSpeed()), as before. sqrt(1 + t²) - 1 is written as t² / (sqrt(1 + t²) + 1) for a small loss tangent to keep the precision; the plain form for a large one also gives the factor 0 for a material with resistivity 0 (infinite loss tangent).

Why the exact attenuation constant and not exp(-k z tan(delta))

Both agree for a small loss tangent (0.0005 dB apart for the wall above). They differ for a large one, which Material produces at a low frequency: tan(delta) = 1 / (2 pi f rho eps_r eps_0) is 4.0 for concrete at 10 MHz and 40 at 1 MHz. In the cited formula k tan(delta) = sqrt(eps_r) / (rho eps_r eps_0 c) does not depend on the frequency, so it gives 1.54 dB for the 0.2 m wall at every frequency from 1 MHz to 5 GHz. A conductor attenuates as sqrt(tan(delta)), and the exact expression has that limit: 0.964 dB at 10 MHz and 0.341 dB at 1 MHz. It costs one more sqrt and no new parameter.

What changes for a user

The dielectric loss in dB is half of the former value for a loss tangent below 0.1 (ratio 0.50 at 0.01, 0.52 at 0.5), lower than before up to a loss tangent of about 4.6, and higher above it (ratio 1.45 at 10, 2.86 at 40). The INET materials at 2.4 GHz have tan(delta) 0.017 (concrete), 5.5e-4 (brick) and 1e-12 (glass), so walls become more transparent. A material with resistivity 0 blocked a signal by exp(-pi k z) before and blocks it completely now. Reflection loss and everything else are unchanged. Release note: doc/whatsnew/fixes/dielectricobstacleloss-loss-exponent.txt.

Commit

  1. DielectricObstacleLoss: fix: compute the dielectric loss as the power decay of a plane wave: the formula, the unit test tests/unit/ObstacleLoss_Dielectric.test with its helper module ObstacleLossTest in tests/unit/lib, the release note, and the 21 fingerprints that move. This commit changes behavior.

The change touches computeDielectricLoss() only. No contract, packet content, parameter or feature descriptor changes.

Evidence

Needs a maintainer: 8 tyf rows. The tyf entries of the 8 moved runs (objectcache x3, obstacle Indoor, ieee80211 SignalLevels, spectrum PowerDensityMap, showcases ratecontrol x2) also move, and tests/fingerprint/store.json still holds their old values. None of the 16 tyf entries of these directories reproduces on this build even on master 7ec0d4d (macOS arm64; the other 51 entries do), so I could not record correct values. They need opp_update_fingerprint_test_results on the CI platform before the merge; until then the fingerprint test of these 8 rows is red. Calculated here, before -> after: NoRateControl c4af-9f29 -> 2d18-a7da, AarfRateControl edbe-d46f -> a848-e8b4, Indoor ae40-be2e -> 8dc2-9deb, SignalLevels 4cb5-a82b -> 2a31-6482, PowerDensityMap fcb6-60c1 -> a29f-2728, objectcache f857-fb4b -> 9a7e-e0c4 (Bvh, Grid) and 94b2-b17a -> 88d3-a361 (WithoutCache). The 8 unchanged runs give the same tyf value before and after.

Unit test, release build (make MODE=release in src and in tests/unit/lib), from tests/unit with opp_test gen and opp_test run -p <runner>, the runner being opp_run -u Cmdenv -l src/INET -l tests/unit/lib/test -n src:tests/unit/lib:. (opp_run_unit_tests of the CI workflow is not installed here):

build ObstacleLoss_Dielectric.test
master 7ec0d4d with the new test FAIL: 3.085 dB at 2.4 GHz, 1.024 dB at 10 MHz
with the fix PASS: 1.542 dB and 0.964 dB

A slab of a material with resistivity="0" in the same test network gives inf dB with the fix; master gives exp(-pi k z), 291 dB for this slab at 2.4 GHz, and the precision form alone would give NaN.

Fingerprints: the 67 entries of the 17 configs that use DielectricObstacleLoss (examples/geometry, objectcache, wireless/obstacle, wireless/ratecontrol, showcases/wireless/ratecontrol, visualizer/canvas/ieee80211, visualizer/canvas/spectrum), each run with opp_run -u Cmdenv and the options of the opp_repl fingerprint task for its ingredients (opp_repl is not installed here). On master all 51 tplx/~tNl/~tND entries pass. With the fix 21 of them move and are updated in the commit; the other 30 pass unchanged, and all 51 pass against the updated store.

moved rows ingredients why
examples/wireless/obstacle Indoor, Outdoor; showcases/wireless/ratecontrol NoRateControl, AarfRateControl; showcases/visualizer/canvas/ieee80211 SignalLevels; showcases/visualizer/canvas/spectrum PowerDensityMap tplx, ~tNl, ~tND the walls take less power from the frames, so the SNIR, the receptions, the retries and the rate adaptation change
examples/objectcache BvhObjectCache, GridObjectCache, WithoutCache tplx only a few more frames arrive above the sensitivity of a receiver and the radio hands them to the MAC: 9 more events in WithoutCache (20880 -> 20889), the same frames on the air, so ~tNl and ~tND stay; x adds nothing in this run (t and tx give the same value)

Unchanged, and reproduced before and after: examples/geometry General (intersection computation only), examples/wireless/obstacle Orbit (satellite path), examples/wireless/ratecontrol Mac, showcases/visualizer/canvas/ieee80211 OneNetwork, MultipleNetworks, VisualizingHandover, spectrum Spectrogram and SpectrumFigure.

Gates: check-commits.sh, check-classification.sh, check-whatsnew.sh, check-includes.sh and check-ned-params.sh pass on 7ec0d4d3f3..HEAD (two notes: a body of 432 words, and fingerprint rows that move in two ways, explained above). The patch applies on 7ec0d4d with git am.

Release build, macOS arm64, OMNeT++ 6.5.0, clang; the OSG feature is off and the fingerprint runs use -x with .nedexclusions.

Not run: the tyf rows on the CI platform; the full tests/unit, tests/module and fingerprint suites; debug build; Linux and Windows; the Qt and OSG visualizer builds.

… decay of a plane wave

DielectricObstacleLoss::computeDielectricLoss() returns the power factor that computeObjectLoss() multiplies into the obstacle loss and that the analog models multiply into the reception power. Before this commit the factor was exp(-2 atan(tan(delta)) k z). The page that the code cites, Wikipedia on dielectric loss, gives the power decay as P = P0 exp(-k z tan(delta)), and for a small loss tangent atan(tan(delta)) is tan(delta), so the code applied the decay constant of the field twice: a 0.2 m concrete wall (resistivity 100 Ohm m, relative permittivity 4.5) lost 3.085 dB at 2.4 GHz instead of 1.542 dB.

After this commit the factor is exp(-2 alpha z), where alpha = k sqrt((sqrt(1 + tan(delta)^2) - 1) / 2) is the attenuation constant of a plane wave in a material with the loss tangent tan(delta), and k is the wave number of the lossless material, as before. For a small loss tangent this is the exp(-k z tan(delta)) of the cited page, 0.0005 dB apart at 2.4 GHz. It was chosen over that formula because it also holds for a large loss tangent, which Material produces at a low frequency: k tan(delta) does not depend on the frequency for a material with a constant resistivity, so the cited formula gives 1.54 dB for the 0.2 m wall at every frequency, while a conductor attenuates as the square root of tan(delta). A material with resistivity 0 (infinite loss tangent) gives the factor 0.

The loss of an obstacle is thus smaller than before for a loss tangent below about 4.6, which includes the INET materials at microwave frequencies, and larger above it. The new tests/unit/ObstacleLoss_Dielectric.test sends one transmission through a single concrete slab at 2.4 GHz and at 10 MHz and compares the printed loss with the analytic value; ObstacleLossTest, the module that prints the loss, is new in the test library.

The fingerprints of 21 runs move. In examples/wireless/obstacle Indoor and Outdoor, showcases/wireless/ratecontrol NoRateControl and AarfRateControl, showcases/visualizer/canvas/ieee80211 SignalLevels and showcases/visualizer/canvas/spectrum PowerDensityMap the walls take less power from the frames, so the SNIR and with it the receptions, the retries and the rate adaptation change: tplx, ~tNl and ~tND move. In the three configs of examples/objectcache only tplx moves: a few more frames now arrive above the sensitivity of a receiver, so the radio hands them to the MAC (9 more events in WithoutCache, 20880 to 20889), and nothing on the air changes, so ~tNl and ~tND stay. The tyf entries of these runs also move; they are not regenerated here because they do not reproduce on the build that produced the other values.

Change: src.physicallayer.wireless.common.obstacleloss.DielectricObstacleLoss | behavior.change.fix | test fingerprint whatsnew

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DielectricObstacleLoss: the dielectric loss is twice the power decay of the formula it cites

1 participant