From 24139a67e9ac2b50053e211bc70368811e154be1 Mon Sep 17 00:00:00 2001 From: Serge Barbosa Da Torre Date: Mon, 25 Jan 2021 14:09:30 +0100 Subject: [PATCH] Introduce NTIA fix on Isoltaed ridge. Original fix is at: https://github.com/NTIA/ehata/pull/13/files The code supports both mode: default=OFF, so no change with current operations. To enable, make sure to use SetWinnForumExtensions(True, True) --- .../propagation/ehata/README.md | 4 ++ .../propagation/ehata/ehata.py | 4 +- .../propagation/ehata/ehata_its_py.cpp | 8 ++-- .../propagation/ehata/its/ExtendedHata.cpp | 4 +- .../its/IsolatedRidgeCorrectionFactor.cpp | 38 ++++++++++++++++--- .../propagation/ehata/its/ehata.h | 3 +- 6 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/harness/reference_models/propagation/ehata/README.md b/src/harness/reference_models/propagation/ehata/README.md index a26573a1d..4184361e0 100644 --- a/src/harness/reference_models/propagation/ehata/README.md +++ b/src/harness/reference_models/propagation/ehata/README.md @@ -45,6 +45,10 @@ The modification relates mostly to: between 3km and 15km (due to an issue in original formulas), and to use terrain strictly included within the 3km and 15km range. +A E-Hata correction about isolated ridge correction is also provided with a +second argument, by specifying: `SetWinnfForumExtensions(True, True)`. +By default this correction is OFF (`=False`). + In addition all the code has been ported to use double instead of float, using a global #define in `ehata.h`. This allows much more consistent results across existing or future implementations. diff --git a/src/harness/reference_models/propagation/ehata/ehata.py b/src/harness/reference_models/propagation/ehata/ehata.py index 662651b97..27a484508 100644 --- a/src/harness/reference_models/propagation/ehata/ehata.py +++ b/src/harness/reference_models/propagation/ehata/ehata.py @@ -24,11 +24,11 @@ ' python setup.py build_ext -i') -def SetWinnForumExtensions(on): +def SetWinnForumExtensions(on, isolated_ridge_corr=False): """Activates/Deactivate the Winnforum extensions. By default they are ON. """ - ehata_its.SetWinnForumExtensions(on) + ehata_its.SetWinnForumExtensions(on, isolated_ridge_corr) def ExtendedHata(its_elev, freq_mhz, height_tx, height_rx, region_code): """Computes the E-Hata propagation path loss. diff --git a/src/harness/reference_models/propagation/ehata/ehata_its_py.cpp b/src/harness/reference_models/propagation/ehata/ehata_its_py.cpp index 34612c6b7..b508bc62f 100644 --- a/src/harness/reference_models/propagation/ehata/ehata_its_py.cpp +++ b/src/harness/reference_models/propagation/ehata/ehata_its_py.cpp @@ -123,13 +123,15 @@ static PyObject* MedianBasicPropLoss(PyObject* self, PyObject* args) { static PyObject* SetWinnForumExtensions(PyObject* self, PyObject* args) { PyObject *val = NULL; - if (!PyArg_ParseTuple(args, "O:ehata_its_SetWinnForumExtensions", - &val)) { + PyObject *isolated_ridge_corr = NULL; + if (!PyArg_ParseTuple(args, "OO:ehata_its_SetWinnForumExtensions", + &val, &isolated_ridge_corr)) { return NULL; } bool on = PyObject_IsTrue(val); + bool do_isolated_ridge_corr = PyObject_IsTrue(isolated_ridge_corr); - SetWinnForumExtensions(on); + SetWinnForumExtensions(on, do_isolated_ridge_corr); Py_RETURN_NONE; } diff --git a/src/harness/reference_models/propagation/ehata/its/ExtendedHata.cpp b/src/harness/reference_models/propagation/ehata/its/ExtendedHata.cpp index bb10636c8..7fb823cdd 100644 --- a/src/harness/reference_models/propagation/ehata/its/ExtendedHata.cpp +++ b/src/harness/reference_models/propagation/ehata/its/ExtendedHata.cpp @@ -6,9 +6,11 @@ // Activation of the WinnForum modifications bool _WinnForum_Extensions = true; // on by default -void SetWinnForumExtensions(bool on) +bool _do_isolated_ridge_v2_corr = false; // off by default +void SetWinnForumExtensions(bool on, bool isolated_ridge_v2_corr) { _WinnForum_Extensions = on; + _do_isolated_ridge_v2_corr = isolated_ridge_v2_corr; } // Definition of the profile distance calculation routine - see ehata.h diff --git a/src/harness/reference_models/propagation/ehata/its/IsolatedRidgeCorrectionFactor.cpp b/src/harness/reference_models/propagation/ehata/its/IsolatedRidgeCorrectionFactor.cpp index 5e90ddb9a..3b18fa13d 100644 --- a/src/harness/reference_models/propagation/ehata/its/IsolatedRidgeCorrectionFactor.cpp +++ b/src/harness/reference_models/propagation/ehata/its/IsolatedRidgeCorrectionFactor.cpp @@ -8,33 +8,59 @@ * d1_hzn__km : horizon distance, in kilometers * d2_hzn__km : horizon distance, in kilometers * h_edge__meter : intermediate value +* do_v2_corr: apply correction v3.2. See https://github.com/NTIA/ehata/pull/13 * Return: * [double] : correction factor */ -double IsolatedRidgeCorrectionFactor(double d1_hzn__km, double d2_hzn__km, double h_edge__meter) +double IsolatedRidgeCorrectionFactor(double d1_hzn__km, double d2_hzn__km, + double h_edge__meter) { double d_1__km[3] = { 15.0, 30.0, 60.0 }; double d_2__km[9] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 }; - // points from Figure 31, Okumura + // points from Figure 31, Okumura, at corresponding d2 distances double curve_data[3][9] = { { 4.0, -13.0, -17.5, -17.5, -15.0, -12.5, -10.0, -8.0, -6.0 }, // C curve : d1 <= 15 km { 12.0, -8.5, -13.0, -12.0, -10.0, -8.0, -6.5, -5.0, -4.0 }, // B curve : d1 <= 30 km { 20.0, -4.0, -6.5, -6.0, -4.5, -3.5, -2.5, -2.0, -1.0 } }; // A curve : d1 <= 60 km - // normalized ridge height factor - double alpha = sqrt(h_edge__meter / 200.0); // Eq 1, Okumura, alpha = 0.07 * sqrt(h) + // Eq 1, Okumura, alpha = 0.07 * sqrt(h) + // Note: 0.07 is approx sqrt (1/ 200), with 200 being the normalization height + double alpha = sqrt(h_edge__meter / 200.0); int id1 = 0; if (d1_hzn__km >= d_1__km[1]) id1 = 1; - int id2 = 0; + // select the first d2 curve distance that is <= to actual path d2 distance + int id2 = 0; while (id2 < 7 && d2_hzn__km > d_2__km[id2 + 1]) id2 = id2 + 1; + // c1 is value on "lower" curve in Figure 31, Okumura, relative to d1 - either curve B or C + // c2 is value on "upper" curve in Figure 31, Okumura, relative to d1 - either curve A or B double c1 = curve_data[id1][id2] + (curve_data[id1][id2 + 1] - curve_data[id1][id2]) * (d2_hzn__km - d_2__km[id2]) / (d_2__km[id2 + 1] - d_2__km[id2]); double c2 = curve_data[id1 + 1][id2] + (curve_data[id1 + 1][id2 + 1] - curve_data[id1 + 1][id2]) * (d2_hzn__km - d_2__km[id2]) / (d_2__km[id2 + 1] - d_2__km[id2]); - return alpha * (c1 + (c2 - c1) * (d1_hzn__km - d_1__km[id1]) / (d_1__km[id1 + 1] - d_1__km[id1])); + if (!_do_isolated_ridge_v2_corr) { + return alpha * (c1 + (c2 - c1) * (d1_hzn__km - d_1__km[id1]) / (d_1__km[id1 + 1] - d_1__km[id1])); + } else { + // compute isolated ridge correction factor, K_im, from Figure 31, Okumura + double K_im; + if (d1_hzn__km <= 15) // clamp to curve C + K_im = c1; + else if (d1_hzn__km >= 60) // clamp to curve A + K_im = c2; + else // interpolate between curves + K_im = (c1 + (c2 - c1) * (d1_hzn__km - d_1__km[id1]) / (d_1__km[id1 + 1] - d_1__km[id1])); + + // clamp K_im asymptote value to 0 dB (to avoid causing a non-physical gain from occuring) + // allow the gain to occur for portion of the curve with d2 distances close to or equal to 0 km + if (d2_hzn__km > 2) + K_im = MIN(K_im, 0); + + // apply conversion factor to account for ridge height, Figure 32, Okumura + double L_iso__db = alpha * K_im; + return L_iso__db; + } } diff --git a/src/harness/reference_models/propagation/ehata/its/ehata.h b/src/harness/reference_models/propagation/ehata/its/ehata.h index e4f95f26f..ca319d614 100644 --- a/src/harness/reference_models/propagation/ehata/its/ehata.h +++ b/src/harness/reference_models/propagation/ehata/its/ehata.h @@ -14,7 +14,8 @@ // ******* WinnForum extension ******* // Activate the Winnforum extensions extern bool _WinnForum_Extensions; // default is ON -void SetWinnForumExtensions(bool on); +extern bool _do_isolated_ridge_v2_corr; // default is OFF +void SetWinnForumExtensions(bool on, bool isolated_ridge_v2_corr); // Function to get the distance in meters from a profile: // the `pfl` profile store the number of points and the step between