Esempio n. 1
0
        public static double BodyNoiseTemp(RealAntenna rx, CelestialBody body, Vector3d rxPointing)
        {
            if (rx.Shape == AntennaShape.Omni)
            {
                return(0);                                  // No purpose in per-body noise temp for an omni.
            }
            Vector3 toBody = body.position - rx.Position;
            double  angle  = Vector3.Angle(rxPointing, toBody);

            //            if (rx.GainAtAngle(Convert.ToSingle(angle)) < 0)
            if (rx.Beamwidth < angle)
            {
                return(0);                       // Pointed too far away
            }
            double bw         = rx.Beamwidth;
            double t          = body.GetTemperature(1); // TODO: Get the BLACKBODY temperature!
            double d          = body.Radius * 2;
            double Rsqr       = (rx.Position - body.position).sqrMagnitude;
            double G          = RATools.LinearScale(rx.Gain);
            double angleRatio = angle / bw;
            double result     = (t * G * d * d / (16 * Rsqr)) * Math.Pow(Math.E, -2.77 * angleRatio * angleRatio);

            //            Debug.LogFormat("Planetary Body Noise Power Estimator: Body {0} base temp {1:F0} diameter {2:F0}km at {3:F2}Mm Gain {4:F1} vs HPBW {5:F1} incident angle {6:F1} yields {7:F1}K", body, t, d/1000, (rx.Position - body.position).magnitude/1e6, G, bw, angle, result);
            return(result);
        }
Esempio n. 2
0
 public static double MinimumTheoreticalEbN0(double SpectralEfficiency)
 {
     // Given SpectralEfficiency in bits/sec/Hz (= Channel Capacity / Bandwidth)
     // Solve Shannon Hartley for Eb/N0 >= (2^(C/B) - 1) / (C/B)
     return(RATools.LogScale(Math.Pow(2, SpectralEfficiency) - 1) / SpectralEfficiency);
     // 1=> 0dB, 2=> 1.7dB, 3=> 3.7dB, 4=> 5.7dB, 5=> 8dB, 6=> 10.2dB, 7=> 12.6dB, 8=> 15dB
     // 9=> 17.6dB, 10=> 20.1dB, 11=> 22.7dB, 20=> 47.2dB
     // 0.5 => -0.8dB.  Rate 1/2 BPSK Turbo code is EbN0 = +1dB, so about 1.8 above Shannon?
 }
Esempio n. 3
0
        public static double AtmosphereMeanEffectiveTemp(double CD) => 255 + (25 * CD);                                                 // 0 <= CD <= 1

        public static double AtmosphereNoiseTemperature(double elevationAngle, double frequency = 1e9)
        {
            float  CD         = 0.5f;
            double Atheta     = AtmosphereAttenuation(CD, elevationAngle, frequency);
            double LossFactor = RATools.LinearScale(Atheta);  // typical values = 1.01 to 2.0 (A = 0.04 dB to 3 dB)
            double meanTemp   = AtmosphereMeanEffectiveTemp(CD);
            double result     = meanTemp * (1 - (1 / LossFactor));

//            Debug.LogFormat("AtmosphereNoiseTemperature calc for elevation {0:F2} freq {1:F2}GHz yielded attenuation {2:F2}, LossFactor {3:F2} and mean temp {4:F2} for result {5:F2}", elevationAngle, frequency/1e9, Atheta, LossFactor, meanTemp, result);
            return(result);
        }
Esempio n. 4
0
        public static double GainFromReference(double refGain, double refFreq, double newFreq)
        {
            double gain = 0;

            if (refGain > 0)
            {
                gain  = refGain;
                gain += (refGain <= RealAntenna.MaxOmniGain) ? 0 : RATools.LogScale(newFreq / refFreq);
            }
            return(gain);
        }
Esempio n. 5
0
        public static double GainFromDishDiamater(double diameter, double freq, double efficiency = 1)
        {
            double gain = 0;

            if (diameter > 0 && efficiency > 0)
            {
                double wavelength = Physics.c / freq;
                gain = RATools.LogScale(9.87 * efficiency * diameter * diameter / (wavelength * wavelength));
            }
            return(gain);
        }
Esempio n. 6
0
        public static float GainFromReference(float refGain, float refFreq, float newFreq)
        {
            float gain = 0;

            if (refGain > 0)
            {
                gain  = refGain;
                gain += (refGain <= MaxOmniGain) ? 0 : RATools.LogScale(newFreq / refFreq);
            }
            return(gain);
        }
Esempio n. 7
0
        public static float GainFromDishDiamater(float diameter, float freq, float efficiency = 1)
        {
            float gain = 0;

            if (diameter > 0 && efficiency > 0)
            {
                float wavelength = Physics.c / freq;
                gain = RATools.LogScale(9.87f * efficiency * diameter * diameter / (wavelength * wavelength));
            }
            return(gain);
        }
Esempio n. 8
0
        public static float CosmicBackgroundTemp(double3 surfaceNormal, double3 toOrigin, float freq, bool isHome)
        {
            float lossFactor = 1;

            if (isHome)
            {
                float CD        = 0.5f;
                float angle     = (float)MathUtils.Angle2(surfaceNormal, toOrigin);
                float elevation = math.max(0, 90.0f - angle);
                lossFactor = Convert.ToSingle(RATools.LinearScale(AtmosphereAttenuation(CD, elevation, freq)));
            }
            return(CMB / lossFactor);
        }
Esempio n. 9
0
        private static double CosmicBackgroundTemp(RealAntenna rx, Vector3d origin)
        {
            double CMB        = 2.725;
            double lossFactor = 1;

            if (rx.ParentNode is RACommNode rxNode && rxNode.ParentBody != null)
            {
                float    CD        = 0.5f;
                Vector3d normal    = rxNode.GetSurfaceNormalVector();
                Vector3d to_origin = origin - rx.Position;
                double   angle     = Vector3d.Angle(normal, to_origin);
                double   elevation = Math.Max(0, 90.0 - angle);
                lossFactor = RATools.LinearScale(AtmosphereAttenuation(CD, elevation, rx.Frequency));
            }
            return(CMB / lossFactor);
        }
Esempio n. 10
0
 public override void OnAwake()
 {
     if (RealAntennas.Network.CommNetPatcher.GetCommNetScenarioModule() is ProtoScenarioModule psm)
     {
         Debug.Log($"{ModTag} Scenario check: Found {RATools.DisplayGamescenes(psm)}");
         if (!RealAntennas.Network.CommNetPatcher.CommNetPatched(psm))
         {
             RealAntennas.Network.CommNetPatcher.UnloadCommNet();
             DestroyNetwork();
             RebuildHomes();
             Debug.Log($"{ModTag} Ignore CommNetScenario ERR immediately following this.");
         }
     }
     if (CommNetEnabled)     // Don't self-delete if we are not enabled.
     {
         base.OnAwake();     // Will set CommNetScenario.Instance to this
     }
 }
Esempio n. 11
0
 public static double Beamwidth(double gain) => Math.Sqrt(52525 / RATools.LinearScale(gain));
Esempio n. 12
0
 public static float Beamwidth(float gain) => math.sqrt(52525 / RATools.LinearScale(gain));
Esempio n. 13
0
        //double baseTemp = body.atmosphere ? body.GetTemperature(1) : GetEquilibriumTemperature(body) + body.coreTemperatureOffset;
        //return body.isStar ? StarRadioTemp(baseTemp, rx.Frequency) : baseTemp;      // TODO: Get the BLACKBODY temperature!


        public static float BodyNoiseTemp(double3 antPos,
                                          float gain,
                                          double3 dir,
                                          double3 bodyPos,
                                          float bodyRadius,
                                          float bodyTemp,
                                          float beamwidth = -1)
        {
            if (gain < MaxOmniGain)
            {
                return(0);
            }
            if (bodyTemp < float.Epsilon)
            {
                return(0);
            }
            double3 toBody   = bodyPos - antPos;
            float   angle    = (float)MathUtils.Angle2(toBody, dir);
            float   distance = (float)math.length(toBody);

            beamwidth = (beamwidth < 0) ? Beamwidth(gain) : beamwidth;
            float bodyRadiusAngularRad = (distance > 10 * bodyRadius)
                    ? math.atan2(bodyRadius, distance)
                    : math.radians(MathUtils.AngularRadius(bodyRadius, distance));
            float bodyRadiusAngularDeg = math.degrees(bodyRadiusAngularRad);

            if (beamwidth < angle - bodyRadiusAngularDeg)
            {
                return(0);                                           // Pointed too far away
            }
            float angleRad     = math.radians(angle);
            float beamwidthRad = math.radians(beamwidth);
            float gainDelta; // Antenna Pointing adjustment
            float viewedAreaBase;

            // How much of the body is in view of the antenna?
            if (beamwidth < bodyRadiusAngularDeg - angle)    // Antenna viewable area completely enclosed by body
            {
                viewedAreaBase = math.PI * beamwidthRad * beamwidthRad;
                gainDelta      = 0;
            }
            else if (beamwidth > bodyRadiusAngularDeg + angle)   // Antenna viewable area completely encloses body
            {
                viewedAreaBase = math.PI * bodyRadiusAngularRad * bodyRadiusAngularRad;
                gainDelta      = -PointingLoss(angle, beamwidth);
            }
            else
            {
                viewedAreaBase = MathUtils.CircleCircleIntersectionArea(beamwidthRad, bodyRadiusAngularRad, angleRad);
                float intersectionCenter = MathUtils.CircleCircleIntersectionOffset(beamwidthRad, bodyRadiusAngularRad, angleRad);
                gainDelta = -PointingLoss(math.degrees(intersectionCenter + beamwidthRad) / 2, beamwidth);
            }

            // How much of the antenna viewable area is occupied by the body
            float antennaViewableArea = math.PI * beamwidthRad * beamwidthRad;
            float viewableAreaRatio   = viewedAreaBase / antennaViewableArea;

            /*
             * double d = body.Radius * 2;
             * double Rsqr = toBody.sqrMagnitude;
             * double G = RATools.LinearScale(rx.Gain);
             * double angleRatio = angle / rx.Beamwidth;
             *
             * // https://deepspace.jpl.nasa.gov/dsndocs/810-005/Binder/810-005_Binder_Change51.pdf Module 105: 2.4.3 Planetary Noise estimator
             * // This estimator is correct for the DSN viewing planets, but wrong for the sun & moon.
             * double result = (t * G * d * d / (16 * Rsqr)) * Math.Pow(Math.E, -2.77 * angleRatio * angleRatio);
             */

            float result = bodyTemp * viewableAreaRatio * RATools.LinearScale(gainDelta);

            //Debug.Log($"Planetary Body Noise Power Estimator: Body {body} Temp: {bodyTemp:F0} AngularDiameter: {bodyRadiusAngularDeg * 2:F1} @ {angle:F1} HPBW: {rx.Beamwidth:F1} ViewableAreaRatio: {viewableAreaRatio:F2} gainDelta: {gainDelta:F4} result: {result}");
            return(result);
        }
Esempio n. 14
0
 public override string ToString() => $"{name} L:{Level} MaxP:{MaxPower:N0}dBm MaxRate:{RATools.PrettyPrintDataRate(MaxDataRate)} Eff:{PowerEfficiency:F4}";
Esempio n. 15
0
        public static double AtmosphereAttenuation(float CD, double elevationAngle, double frequency = 1e9)
        {
            double AirMasses = (1 / Math.Sin(RATools.DegToRad(Math.Abs(elevationAngle))));

            return(AtmosphereZenithAttenuation(CD, frequency) * AirMasses);
        }
Esempio n. 16
0
        public static double BodyNoiseTemp(RealAntenna rx, CelestialBody body, Vector3d rxPointing)
        {
            if (rx.Shape == AntennaShape.Omni)
            {
                return(0);                                  // No purpose in per-body noise temp for an omni.
            }
            Vector3 toBody               = body.position - rx.Position;
            double  angle                = Vector3.Angle(rxPointing, toBody);
            double  distance             = toBody.magnitude;
            double  bodyRadiusAngularRad = (distance > 10 * body.Radius)
                    ? Math.Atan2(body.Radius, distance)
                    : MathUtils.AngularRadius(body.Radius, distance) * Mathf.Deg2Rad;
            double bodyRadiusAngularDeg = bodyRadiusAngularRad * Mathf.Rad2Deg;

            if (rx.Beamwidth < angle - bodyRadiusAngularDeg)
            {
                return(0);                                              // Pointed too far away
            }
            double baseTemp = body.atmosphere ? body.GetTemperature(1) : GetEquilibriumTemperature(body) + body.coreTemperatureOffset;
            double t        = body.isStar ? StarRadioTemp(baseTemp, rx.Frequency) : baseTemp; // TODO: Get the BLACKBODY temperature!

            if (t < double.Epsilon)
            {
                return(0);
            }

            double angleRad     = angle * Mathf.Deg2Rad;
            double beamwidthRad = rx.Beamwidth * Mathf.Deg2Rad;
            double gainDelta; // Antenna Pointing adjustment
            double viewedAreaBase;

            // How much of the body is in view of the antenna?
            if (rx.Beamwidth < bodyRadiusAngularDeg - angle)    // Antenna viewable area completely enclosed by body
            {
                viewedAreaBase = Mathf.PI * beamwidthRad * beamwidthRad;
                gainDelta      = 0;
            }
            else if (rx.Beamwidth > bodyRadiusAngularDeg + angle)   // Antenna viewable area completely encloses body
            {
                viewedAreaBase = Mathf.PI * bodyRadiusAngularRad * bodyRadiusAngularRad;
                gainDelta      = rx.GainAtAngle(angle) - rx.Gain;
            }
            else
            {
                viewedAreaBase = MathUtils.CircleCircleIntersectionArea(beamwidthRad, bodyRadiusAngularRad, angleRad);
                double intersectionCenter = MathUtils.CircleCircleIntersectionOffset(beamwidthRad, bodyRadiusAngularRad, angleRad);
                gainDelta = rx.GainAtAngle((intersectionCenter + beamwidthRad) * Mathf.Rad2Deg / 2) - rx.Gain;
            }

            // How much of the antenna viewable area is occupied by the body
            double antennaViewableArea = Mathf.PI * beamwidthRad * beamwidthRad;
            double viewableAreaRatio   = viewedAreaBase / antennaViewableArea;

            /*
             * double d = body.Radius * 2;
             * double Rsqr = toBody.sqrMagnitude;
             * double G = RATools.LinearScale(rx.Gain);
             * double angleRatio = angle / rx.Beamwidth;
             *
             * // https://deepspace.jpl.nasa.gov/dsndocs/810-005/Binder/810-005_Binder_Change51.pdf Module 105: 2.4.3 Planetary Noise estimator
             * // This estimator is correct for the DSN viewing planets, but wrong for the sun & moon.
             * double result = (t * G * d * d / (16 * Rsqr)) * Math.Pow(Math.E, -2.77 * angleRatio * angleRatio);
             */

            double result = t * viewableAreaRatio * RATools.LinearScale(gainDelta);

            //Debug.Log($"Planetary Body Noise Power Estimator: Body {body} Temp: {t:F0} AngularDiameter: {bodyRadiusAngularDeg * 2:F1} @ {angle:F1} HPBW: {rx.Beamwidth:F1} ViewableAreaRatio: {viewableAreaRatio:F2} gainDelta: {gainDelta:F4} result: {result}");
            return(result);
        }
Esempio n. 17
0
        private bool BestPeerModulator(RealAntenna rx, out double modRate, out double codeRate)
        {
            RealAntennaDigital tx = this;

            Antenna.Encoder encoder = Antenna.Encoder.BestMatching(tx.Encoder, rx.Encoder);
            codeRate = encoder.CodingRate;
            modRate  = 0;
            if (!(rx is RealAntennaDigital))
            {
                return(false);
            }
            if (!Compatible(rx))
            {
                return(false);
            }
            if ((tx.Parent is ModuleRealAntenna) && !tx.Parent.CanComm())
            {
                return(false);
            }
            if ((rx.Parent is ModuleRealAntenna) && !rx.Parent.CanComm())
            {
                return(false);
            }

            Vector3     toSource = rx.Position - tx.Position;
            double      distance = toSource.magnitude;
            RAModulator txMod = tx.modulator, rxMod = (rx as RealAntennaDigital).modulator;

            if ((distance < tx.MinimumDistance) || (distance < rx.MinimumDistance))
            {
                return(false);
            }
            if (!txMod.Compatible(rxMod))
            {
                return(false);
            }
            int    maxBits       = Math.Min(txMod.ModulationBits, rxMod.ModulationBits);
            double maxSymbolRate = Math.Min(txMod.SymbolRate, rxMod.SymbolRate);
            double minSymbolRate = Math.Max(txMod.MinSymbolRate, rxMod.MinSymbolRate);

            double RxPower       = Physics.ReceivedPower(tx, rx, distance, tx.Frequency);
            double temp          = Physics.NoiseTemperature(rx, tx.Position);
            double N0            = Physics.NoiseSpectralDensity(temp); // In dBm
            double minEb         = encoder.RequiredEbN0 + N0;          // in dBm
            double maxBitRateLog = RxPower - minEb;                    // in dB*Hz
            double maxBitRate    = RATools.LinearScale(maxBitRateLog);

            /*
             * Vessel tv = (tx.ParentNode as RACommNode).ParentVessel;
             * Vessel rv = (rx.ParentNode as RACommNode).ParentVessel;
             * if (tv != null && rv != null)
             * {
             *  string debugStr = $"{ModTag} {tx} to {rx} RxP {RxPower:F2} vs temp {temp:F2}. NSD {N0:F1}, ReqEb/N0 {encoder.RequiredEbN0:F1} -> minEb {minEb:F1} gives maxRate {RATools.PrettyPrint(maxBitRate)}bps vs symbol rates {RATools.PrettyPrint(minSymbolRate)}Sps-{RATools.PrettyPrint(maxSymbolRate)}Sps";
             *  Debug.Log(debugStr);
             * }
             */
            // We cannot slow our modulation enough to achieve the required Eb/N0, so fail.
            if (maxBitRate < minSymbolRate)
            {
                return(false);
            }
            double targetRate;
            int    negotiatedBits;

            if (maxBitRate <= maxSymbolRate)
            {
                // The required Eb/N0 occurs at a lower symbol rate than we are capable of at 1 bit/sec/Hz.
                // Step down the symbol rate and modulate at 1 bit/sec/Hz (BPSK).
                // (What if the modulator only supports schemes with >1 bits/symbol?)
                // (Then our minimum EbN0 is an underestimate.)
                float  ratio = Convert.ToSingle(maxBitRate / maxSymbolRate);
                double log2  = Math.Floor(Mathf.Log(ratio, 2));
                targetRate     = maxSymbolRate * Math.Pow(2, log2);
                negotiatedBits = 1;
                //debugStr += $" Selected rate {RATools.PrettyPrint(targetRate)}bps (MaxSymbolRate * log2 {log2})";
            }
            else
            {
                // We need to go to SNR here and rely a bit more on Shannon-Hartley
                double Noise  = N0 + RATools.LogScale(maxSymbolRate);
                double CI     = RxPower - Noise;
                double margin = CI - encoder.RequiredEbN0;
                targetRate     = maxSymbolRate;
                negotiatedBits = Math.Min(maxBits, Convert.ToInt32(1 + Math.Floor(margin / 3)));
                //debugStr += $" Noise {Noise:F2} CI {CI:F2} margin {margin:F1}";
            }
            modRate = targetRate * negotiatedBits;
            //Debug.LogFormat(debugStr);
            return(true);

            // Energy/bit (Eb) = Received Power / datarate
            // N0 = Noise Spectral Density = K*T
            // Noise = N0 * BW
            // SNR = RxPower / Noise = RxPower / (N0 * BW) = Eb*datarate / N0*BW  = (Eb/N0) * (datarate/BW)
            // I < B * log(1 + S/N)   where I = information rate, B=Bandwidth, S=Total Power, N=Total Noise Power = N0*B
            //
            // Es/N0 = (Total Power / Symbol Rate) / N0
            // = Eb/N0 * log(modulation order)
        }
Esempio n. 18
0
 public override string ToString() => $"{BitsToString(ModulationBits)} {RATools.PrettyPrintDataRate(DataRate)}";