Beispiel #1
0
 public static float BodyNoiseTemp(RealAntenna rx, CelestialBody body, Vector3d rxPointing) =>
 BodyNoiseTemp(new double3(rx.PrecisePosition.x, rx.PrecisePosition.y, rx.PrecisePosition.z),
               rx.Gain,
               new double3(rxPointing.x, rxPointing.y, rxPointing.z),
               new double3(body.position.x, body.position.y, body.position.z),
               (float)body.Radius,
               body.isStar ? StarRadioTemp(BodyBaseTemperature(body), rx.Frequency) : BodyBaseTemperature(body));
Beispiel #2
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);
        }
 public RealAntennaDigital(RealAntenna orig) : base(orig)
 {
     if (orig is RealAntennaDigital o)
     {
         modulator = new RAModulator(o.modulator);
     }
 }
Beispiel #4
0
 private static double AntennaMicrowaveTemp(RealAntenna rx)
 {
     if ((rx.ParentNode as RACommNode)?.ParentVessel is Vessel)
     {
         return(rx.TechLevelInfo.ReceiverNoiseTemperature);
     }
     return(rx.AMWTemp);
 }
Beispiel #5
0
 public static float AtmosphericTemp(RealAntenna rx, Vector3d origin)
 {
     if (rx.ParentNode is RACommNode rxNode && rxNode.ParentBody != null)
     {
         Vector3d normal = rxNode.GetSurfaceNormalVector();
         return(AtmosphericTemp(new double3(rx.Position.x, rx.Position.y, rx.Position.z),
                                new double3(normal.x, normal.y, normal.z),
                                new double3(origin.x, origin.y, origin.z),
                                rx.Frequency));
     }
     return(0);
 }
        void GUIDisplay(int windowID)
        {
            string s = $"{(sourceAntenna?.ParentNode as RACommNode)?.ParentVessel?.vesselName} {sourceAntenna?.ToStringShort()}";

            GUILayout.Label($"Antenna: {(sourceAntenna is RealAntenna ? s : "Not Selected")}");
            GUILayout.BeginHorizontal();
            GUILayout.BeginVertical();
            if (GUILayout.Button($"Source Sort Mode: {sourceSortMode}"))
            {
                //(i1, i2) => i1.ToString().CompareTo(i2.ToString())
                sourceSortMode = (SortMode)(((int)(sourceSortMode + 1)) % System.Enum.GetNames(typeof(SortMode)).Length);
                SortList(sourceVessels, sourceSortMode);
            }
            scrollSourcePos = GUILayout.BeginScrollView(scrollSourcePos, GUILayout.ExpandWidth(true));
            foreach (var ra in from Vessel v in sourceVessels
                     from RealAntenna ra in (v.Connection?.Comm as RACommNode)?.RAAntennaList?.Where(x => x.CanTarget)
                     select ra)
            {
                if (GUILayout.Button($"{(ra.ParentNode as RACommNode)?.ParentVessel?.vesselName} {ra.ToStringShort()}"))
                {
                    sourceAntenna = ra;
                }
            }
            GUILayout.EndScrollView();
            GUILayout.EndVertical();

            GUILayout.BeginVertical();
            if (GUILayout.Button($"Target Sort Mode: {targetSortMode}"))
            {
                targetSortMode = (SortMode)(((int)(targetSortMode + 1)) % System.Enum.GetNames(typeof(SortMode)).Length);
                SortList(targetVessels, targetSortMode);
            }
            scrollTargetPos = GUILayout.BeginScrollView(scrollTargetPos, GUILayout.ExpandWidth(true));
            foreach (var v in targetVessels)
            {
                if (sourceAntenna is RealAntenna && GUILayout.Button($"{v.vesselName}"))
                {
                    sourceAntenna.Target = v;
                }
            }
            foreach (var v in FlightGlobals.Bodies)
            {
                if (sourceAntenna is RealAntenna && GUILayout.Button($"{v.name}"))
                {
                    sourceAntenna.Target = v;
                }
            }
            GUILayout.EndScrollView();
            GUILayout.EndVertical();
            GUILayout.EndHorizontal();

            GUI.DragWindow();
        }
Beispiel #7
0
 private static double AtmosphericTemp(RealAntenna rx, Vector3d origin)
 {
     if (rx.ParentNode is RACommNode rxNode && rxNode.ParentBody != null)
     {
         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);
         return(AtmosphereNoiseTemperature(elevation, rx.Frequency));
     }
     return(0);
 }
Beispiel #8
0
        private static float CosmicBackgroundTemp(RealAntenna rx, Vector3d origin)
        {
            float temp = 3;

            if (rx.ParentNode is RACommNode rxNode)
            {
                Vector3d normal    = (rxNode.ParentBody is CelestialBody) ? rxNode.GetSurfaceNormalVector() : Vector3d.zero;
                Vector3d to_origin = origin - rx.Position;
                temp = CosmicBackgroundTemp(new double3(normal.x, normal.y, normal.z),
                                            new double3(to_origin.x, to_origin.y, to_origin.z),
                                            rx.Frequency,
                                            rxNode.isHome);
            }
            return(temp);
        }
Beispiel #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);
        }
Beispiel #10
0
        public static RealAntenna HighestGainCompatibleDSNAntenna(List <CommNode> nodes, RealAntenna peer)
        {
            RealAntenna result      = null;
            double      highestGain = 0;

            foreach (RACommNode node in nodes.Where(obj => obj.isHome))
            {
                foreach (RealAntenna ra in node.RAAntennaList)
                {
                    if (peer.Compatible(ra) && ra.Gain > highestGain)
                    {
                        highestGain = ra.Gain;
                        result      = ra;
                    }
                }
            }
            return(result);
        }
Beispiel #11
0
        public static double AllBodyTemps(RealAntenna rx, Vector3d rxPointing)
        {
            double temp = 0;

            if (rx.Shape != AntennaShape.Omni)
            {
                Profiler.BeginSample("RA Physics AllBodyTemps MainLoop");
                RACommNode node = rx.ParentNode as RACommNode;
                // Note there are ~33 bodies in RSS.
                foreach (CelestialBody body in FlightGlobals.Bodies)
                {
                    if (!node.isHome || !node.ParentBody.Equals(body))
                    {
                        temp += BodyNoiseTemp(rx, body, rxPointing);
                    }
                }
                Profiler.EndSample();
            }
            return(temp);
        }
Beispiel #12
0
        public static double NoiseTemperature(RealAntenna rx, Vector3d origin)
        {
            double amt    = AntennaMicrowaveTemp(rx);
            double atmos  = AtmosphericTemp(rx, origin);
            double cosmic = CosmicBackgroundTemp(rx, origin);
            //double allbody = (rx.ParentNode.isHome) ? AllBodyTemps(rx, origin - rx.Position) : AllBodyTemps(rx, rx.ToTarget);
            // Home Stations are directional, but treated as always pointing towards the peer.
            double allbody = (rx.ParentNode.isHome) ? AllBodyTemps(rx, origin - rx.Position) : rx.cachedRemoteBodyNoiseTemp;
            double total   = amt + atmos + cosmic + allbody;

            //            Debug.LogFormat("NoiseTemp: Antenna {0:F2}  Atmos: {1:F2}  Cosmic: {2:F2}  Bodies: {3:F2}  Total: {4:F2}", amt, atmos, cosmic, allbody, total);
            return(total);

            //
            // https://www.itu.int/dms_pubrec/itu-r/rec/p/R-REC-P.372-7-200102-S!!PDF-E.pdf
            //
            // Sky Temperature:  curves that vary based on atmosphere composition of a body.
            //   Earth example: http://www.delmarnorth.com/microwave/requirements/satellite_noise.pdf
            //     <10 deg K @ <15GHz and >30deg elevation in clear weather
            //     Rain can be a very large contributor, tho.
            //     At 0 deg elevation, sky temperature is effectively Earth ambient temperature = 290K.
            //     An omni antenna near Earth has a temperature = Earth ambient temperature = 290K.
            //     A directional antenna on a satellite pointed at Earth s.t. the entire main lobe of the ant
            //        is the Earth also has a noise temperature ~= 290K.
            //     A directional antenna pointed at the sun s.t. its main lobe encompasses ONLY the sun
            //        (so very directional) has an antenna temperature ~= 6000K?
            //  Ref: Galactic noise is high below 1000 MHz. At around 150 MHz, it is approximately 1000 K. At 2500 MHz, it has leveled off to around 10 K.
            //  Atmospheric absorption:  Earth example:  <1dB @ <20GHz
            //  Rainfall has a specific attenuation from absorption, and
            //    and a correlated contribution to sky temperature from re-emission.
            //  We should either track the effective temperature of the receiver electronics,
            //    or calculate it from its more conventional notation (to me) of noise figure.
            //  So we can get system temperature = antenna effective temperature + sky temperature + receiver effective temperature
            //  Sky we can "define" based on the near celestial body, or set as 3K for deep space.
            //  Receiver effective temperature we can derive from a noise figure.
            //  Antenna temperature is basically the notion of "sky" temperature + rain temperature, or 3-4K in deep space.
            //
            // P(dBW) = 10*log10(Kb*T*bandwidth) = -228.59917 + 10*log10(T*BW)
        }
Beispiel #13
0
 public static double ReceivedPower(RealAntenna tx, RealAntenna rx, double distance, double frequency = 1e9)
 => tx.TxPower + tx.Gain - PathLoss(distance, frequency) - PointingLoss(tx, rx.Position) - PointingLoss(rx, tx.Position) + rx.Gain;
Beispiel #14
0
 private bool RenderPanel(SelectionMode mode, ref RealAntenna antenna, ref Vector2 scrollPos, in RealAntenna peer, GUIStyle buttonStyle)
Beispiel #15
0
 private static double AntennaMicrowaveTemp(RealAntenna rx) =>
 ((rx.ParentNode as RACommNode)?.ParentBody is CelestialBody) ? rx.AMWTemp : rx.TechLevelInfo.ReceiverNoiseTemperature;
Beispiel #16
0
 public static double NoiseFloor(RealAntenna rx, double noiseTemp) => NoiseSpectralDensity(noiseTemp) + (10 * Math.Log10(rx.Bandwidth));
Beispiel #17
0
        private bool RenderPanel(SelectionMode mode, ref RealAntenna antenna, ref Vector2 scrollPos)
        {
            bool res = false;

            scrollPos = GUILayout.BeginScrollView(scrollPos);
            if (mode == SelectionMode.Vessel)
            {
                if (HighLogic.LoadedSceneIsEditor)
                {
                    foreach (var x in protoVesselAntennaCache)
                    {
                        foreach (RealAntenna ra in x.Value)
                        {
                            if (GUILayout.Button($"{x.Key.vesselName} {ra.ToStringShort()}"))
                            {
                                antenna = ra;
                                res     = true;
                            }
                        }
                    }

                    ShipConstruct sc = EditorLogic.RootPart.ship;
                    foreach (Part p in sc.Parts)
                    {
                        foreach (ModuleRealAntenna mra in p.FindModulesImplementing <ModuleRealAntenna>())
                        {
                            if (GUILayout.Button($"{sc.shipName} {mra.RAAntenna.ToStringShort()}"))
                            {
                                antenna = mra.RAAntenna;
                                res     = true;
                            }
                        }
                    }
                }
                foreach (Vessel v in FlightGlobals.Vessels.Where(x => x.Connection?.Comm is RACommNode))
                {
                    foreach (RealAntenna ra in (v.Connection.Comm as RACommNode).RAAntennaList)
                    {
                        if (GUILayout.Button($"{v.GetDisplayName()} {ra.ToStringShort()}"))
                        {
                            antenna = ra;
                            res     = true;
                        }
                    }
                }
            }
            else
            {
                foreach (Network.RACommNetHome home in RACommNetScenario.GroundStations.Values.Where(x => x.Comm is RACommNode))
                {
                    foreach (RealAntenna ra in home.Comm.RAAntennaList)
                    {
                        if (GUILayout.Button($"{home.nodeName} {ra.ToStringShort()}"))
                        {
                            antenna = ra;
                            res     = true;
                        }
                    }
                }
            }
            GUILayout.EndScrollView();
            return(res);
        }
        public override double BestDataRateToPeer(RealAntenna rx)
        {
            double dataRate = (BestPeerModulator(rx, out double modRate, out double codeRate)) ? modRate * codeRate : 0;

            return(dataRate);
        }
Beispiel #19
0
 public static double PointingLoss(RealAntenna ant, Vector3 origin)
 => (ant.CanTarget && ant.ToTarget != Vector3.zero) ? PointingLoss(Vector3.Angle(origin - ant.Position, ant.ToTarget), ant.Beamwidth) : 0;
Beispiel #20
0
 public static float ReceivedPower(RealAntenna tx, RealAntenna rx, float distance, float frequency = 1e9f)
 => tx.TxPower + tx.Gain - PathLoss(distance, frequency) - PointingLoss(tx, rx.Position) - PointingLoss(rx, tx.Position) + rx.Gain;
Beispiel #21
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);
        }
        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)
        }
Beispiel #23
0
 private static double AntennaMicrowaveTemp(RealAntenna rx) => rx.AMWTemp;