Longley Rice Terrestial Propagation

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;
        }