The Variablity Consideration
The ITM takes into consideration three variabilities, Time, Location, Reliability. This
calculation is empirical statistics. In reality for a STL only reliability is relevant.
Time:
Represents the variation in signal level with time due to different propagation conditions associated
with changing atmospheric conditions.
Location:
Represents the changes expected when the Rx is moved between different locations. Obviously not
relevent for an STL.
Reliability:
A value 0-99 representing percentage of time that the STL is achive the 100% functionality. Note:
this does not mean that the link is non-function only that the time the link is not at the best.
The Method qrpfl
void qlrpfl(Elevations pfl, RadioClimate klimx, VariabilityMode mdvarx, double distance = 0.0)
{
_dist = pfl.EndIndex * pfl.DeltaDistance;
hzns(pfl);
foreach (var antenna in Antennae)
antenna.xl = Math.Min(15 * antenna.hg, 0.1 * antenna.dl);
Receiver.xl = _dist - Receiver.xl;
_dh = d1thx(pfl, Transmitter.xl, Receiver.xl);
if (Transmitter.dl + Receiver.dl > 1.5 * _dist)
{
z1sq1(pfl, Transmitter.xl, Receiver.xl, out var za, out var zb);
Transmitter.he = Transmitter.hg + Dim(pfl.FirstPoint, za);
Receiver.he = Receiver.hg + Dim(pfl.LastPoint, zb);
foreach (var antenna in Antennae)
antenna.dl = Math.Sqrt(2 * antenna.he / _gme) * Math.Exp(-0.07 * Math.Sqrt(_dh / Math.Max(antenna.he, 5)));
var q = Transmitter.dl + Receiver.dl;
if (q <= _dist)
{
q = Math.Pow(_dist / q, 2);
foreach (var antenna in Antennae)
{
antenna.he *= q;
antenna.dl = Math.Sqrt(2 * antenna.he / _gme) * Math.Exp(-0.07 * Math.Sqrt(_dh / Math.Max(antenna.he, 5)));
}
}
foreach (var antenna in Antennae)
{
q = Math.Sqrt(2 * antenna.he / _gme);
antenna.the = (0.65 * _dh * (q / antenna.dl - 1) - 2 * antenna.he) / q;
}
}
else
{
z1sq1(pfl, Transmitter.xl, 0.9 * Transmitter.dl, out var za, out _);
z1sq1(pfl, _dist - 0.9 * Receiver.dl, Receiver.xl, out _, out var zb);
Transmitter.he = Transmitter.hg + Dim(pfl.FirstPoint, za);
Receiver.he = Receiver.hg + Dim(pfl.LastPoint, zb);
}
_mdp = ControlFlow.PointToPoint;
_mdvar = mdvarx;
_klim = klimx;
_lvar = Changes.All;
lrprop(0);
}
The Method hzns to find the horizons
void hzns(Elevations pfl)
{
var np = pfl.EndIndex;
var xi = pfl.DeltaDistance;
var za = pfl.FirstPoint + Transmitter.hg;
var zb = pfl.LastPoint + Receiver.hg;
var qc = 0.5 * _gme;
var q = qc * _dist;
Receiver.the = (zb - za) / _dist;
Transmitter.the = Receiver.the - q;
Receiver.the = -Receiver.the - q;
Transmitter.dl = _dist;
Receiver.dl = _dist;
if (np >= 2)
{
var sa = 0.0;
var sb = _dist;
var wq = true;
for (var i = 1; i < np; i++)
{
sa += xi;
sb -= xi;
q = pfl.Points[i] - (qc * sa + Transmitter.the) * sa - za;
if (q > 0)
{
Transmitter.the += q / sa;
Transmitter.dl = sa;
wq = false;
}
if (!wq)
{
q = pfl.Points[i] - (qc * sb + Receiver.the) * sb - zb;
if (q > 0)
{
Receiver.the += q / sb;
Receiver.dl = sb;
}
}
}
}
}
The Method d1thx to find the interdecile range of elevations.
static Double d1thx(Elevations pfl, Double x1, Double x2)
{
var np = pfl.EndIndex;
var xa = x1 / pfl.DeltaDistance;
var xb = x2 / pfl.DeltaDistance;
if (xb - xa < 2) // exit out
return 0;
var ka = (int)(0.1 * (xb - xa + 8));
ka = Math.Min(Math.Max(4, ka), 25);
var n = 10 * ka - 5;
var kb = n - ka + 1;
Double sn = n - 1;
xb = (xb - xa) / sn;
var k = (int)(xa + 1);
xa -= k;
var s = new Elevations(n, 1);
for (var j = 0; j < n; j++)
{
while (xa > 0 && k < np)
{
xa -= 1;
k++;
}
s.Points[j] = pfl.Points[k] + (pfl.Points[k] - pfl.Points[k - 1]) * xa;
xa += xb;
}
z1sq1(s, 0, sn, out xa, out xb);
xb = (xb - xa) / sn;
for (var j = 0; j < n; j++)
{
s.Points[j] -= xa;
xa += xb;
}
var d1thxv = qtile(n - 1, s.Points, ka - 1) - qtile(n - 1, s.Points, kb - 1);
d1thxv /= 1 - 0.8 * Math.Exp(-(x2 - x1) / 50000.0);
return d1thxv;
}
The Method lrprop to tie things together
double lrprop(Double d) // PaulM_lrprop
{
if (_mdp != ControlFlow.AreaContinue)
{
foreach (var antenna in Antennae)
antenna.dls = Math.Sqrt(2 * antenna.he / _gme);
_dlsa = Transmitter.dls + Receiver.dls;
_dla = Transmitter.dl + Receiver.dl;
_tha = Math.Max(Transmitter.the + Receiver.the, -_dla * _gme);
_wlos = false;
_wscat = false;
if (_wn < 0.419 || _wn > 419) // upper _wn was 210 and 0.838, increased frequency number to 20GHz and decreased to 20MHz
{
_kwx = Math.Max(_kwx, 1);
}
foreach (var antenna in Antennae)
if (antenna.hg < 1 || antenna.hg > 1000)
{
_kwx = Math.Max(_kwx, 1);
}
foreach (var antenna in Antennae)
if (Math.Abs(antenna.the) > 200e-3 || antenna.dl < 0.1 * antenna.dls ||
antenna.dl > 3 * antenna.dls)
{
_kwx = Math.Max(_kwx, 3);
}
if (_ens < 250 || _ens > 400 ||
_gme < 75e-9 || _gme > 250e-9 ||
_zgnd.Real <= Math.Abs(_zgnd.Imaginary) ||
_wn < 0.419 || _wn > 420)
{
_kwx = 4;
}
foreach (var antenna in Antennae)
if (antenna.hg < 0.5 || antenna.hg > 3000)
{
_kwx = 4;
}
_dmin = Math.Abs(Transmitter.he - Receiver.he) / 200e-3;
init_adiff();
_xae = Math.Pow(_wn * Math.Pow(_gme, 2), -THIRD);
var d3 = Math.Max(_dlsa, 1.3787 * _xae + _dla);
var d4 = d3 + 2.7574 * _xae;
var a3 = adiff(d3);
var a4 = adiff(d4);
_emd = (a4 - a3) / (d4 - d3);
_aed = a3 - _emd * d3;
}
if (_mdp != ControlFlow.PointToPoint)
{
_mdp = ControlFlow.PointToPoint;
_dist = d;
}
if (_dist > 0)
{
if (_dist > 1000000)
{
_kwx = Math.Max(_kwx, 1);
}
if (_dist < _dmin)
{
_kwx = Math.Max(_kwx, 3);
}
if (_dist < 100 || _dist > 2000000)
{
_kwx = 4;
}
}
if (_dist < _dlsa)
{
if (!_wlos)
{
init_alos(); // for _wls
var d2 = _dlsa;
var a2 = _aed + d2 * _emd;
var d0 = 1.908 * _wn * Transmitter.he * Receiver.he;
Double d1;
if (_aed >= 0)
{
d0 = Math.Min(d0, 0.5 * _dla);
d1 = d0 + 0.25 * (_dla - d0);
}
else
d1 = Math.Max(-_aed / _emd, 0.25 * _dla);
var a1 = alos(d1);
var wq = false;
if (d0 < d1)
{
var a0 = alos(d0);
var q = Math.Log(d2 / d0);
_ak2 = Math.Max(0, ((d2 - d0) * (a1 - a0) - (d1 - d0) * (a2 - a0)) / ((d2 - d0) * Math.Log(d1 / d0) - (d1 - d0) * q));
wq = _aed >= 0 || _ak2 > 0;
if (wq)
{
_ak1 = (a2 - a0 - _ak2 * q) / (d2 - d0);
if (_ak1 < 0)
{
_ak1 = 0;
_ak2 = Dim(a2, a0) / q;
if (_ak2 == 0)
_ak1 = _emd;
}
}
}
if (!wq)
{
_ak1 = Dim(a2, a1) / (d2 - d1);
_ak2 = 0;
if (_ak1 == 0)
_ak1 = _emd;
}
_ael = a2 - _ak1 * d2 - _ak2 * Math.Log(d2);
_wlos = true;
}
if (_dist > 0)
_aref = _ael + _ak1 * _dist + _ak2 * Math.Log(_dist);
}
if (_dist <= 0 || _dist >= _dlsa)
{
if (!_wscat)
{
init_ascat();
var d5 = _dla + 200000;
var d6 = d5 + 200000;
var a6 = ascat(d6);
var a5 = ascat(d5);
if (a5 < 1000)
{
_ems = (a6 - a5) / 200000.0;
_dx = Math.Max(_dlsa, Math.Max(_dla + 0.3 * _xae * Math.Log(47.7 * _wn), (a5 - _aed - _ems * d5) / (_emd - _ems)));
_aes = (_emd - _ems) * _dx + _aed;
}
else
{
_ems = _emd;
_aes = _aed;
_dx = 10000000;
}
_wscat = true;
}
if (_dist > _dx)
_aref = _aes + _ems * _dist;
else
_aref = _aed + _emd * _dist;
}
_aref = Math.Max(_aref, 0);
return _aref;
}