65.9K
CodeProject 正在变化。 阅读更多。
Home

物理单位的自动转换

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (4投票s)

2014年1月23日

CPOL

11分钟阅读

viewsIcon

18952

Main picture

有用链接

1 简介。

任何高级软件都包含第三方软件。通常第三方软件需要适应自有软件。不同的软件可能使用不同的物理单位。例如,从地面到太空的地球大气经验全球模型 (NRLMSISE-00) 源代码对于大气物理学研究非常方便,但对于弹道学则不方便,因为弹道学使用其他物理单位。物理单位的转换是一项非常重要的任务。

++++++++++++++++++++++

统一单位重要性的一個例子是 NASA火星气候轨道器 任务的失败,该任务于 1999 年 9 月在前往火星的任务中意外被摧毁,未能进入轨道,原因是关于力的单位存在沟通失误:不同的计算机程序使用了不同的测量单位(牛顿磅力)。大量的努力、时间和金钱被浪费了。[6][7]

1999 年 4 月 15 日,大韩航空货运6316 次航班上海飞往首尔的航班因机组人员混淆塔台指令(以米为单位)和高度计读数(以英尺为单位)而失事。造成三名机组人员和地面五人死亡,三十七人受伤。[8][9]

1983 年,一架波音 767(后来被称为金梅冰川滑翔机)由于在计算加拿大航空公司第一架使用公制单位的飞机的燃油供应时出现两次错误,导致飞机在飞行途中燃油耗尽。[10] 这起事故显然是由于同时使用公制和英制单位以及体积和质量单位的混淆所致。

摘自这里

++++++++++++++++++++

有时物理单位的转换需要大量工作,但这项工作可以部分或完全自动化。本文致力于物理单位自动化问题。我的文章包含很多细节,因为我的一些模块可能会引起一些读者的兴趣。本文也可以看作是关于低内聚的实践指南。

2 背景

互联网上有很多有用的信息。然而,通常这些信息需要根据自己的目的进行调整。本文致力于物理单位的自动转换。如果我们拥有信息的提供者和消费者

Provider & consumer

并且消费者的物理单位与提供者的不同,那么我们就需要进行单位转换。我的软件可以部分或完全自动地执行此操作。

2.1 理论问题

理论问题在此解释,以下公式表示转换系数的对数。

Conversion formula.

我使用了上述公式的指数版本。

2.2 系数计算

以下代码包含物理单位的枚举。

     /// <summary>
    /// Types of angle
    /// </summary>
    public enum AngleType
    {
        Radian, // Radian
        Circle, // Circle
        Degree  // Degree
    }

    /// <summary>
    /// Types of length
    /// </summary>
    public enum LengthType
    {
        Meter,      // Meter
        Centimeter, // Centimeter
        Kilometer   // Kilometer
    }

    /// <summary>
    /// Types of time
    /// </summary>
    public enum TimeType
    {
        Second, // Second
        Day     // Day
    }

    /// <summary>
    /// Types of mass
    /// </summary>
    public enum MassType
    {
        Kilogram,   // Kilogram
        Gram        // Gram
    }

以下属性包含物理单位使用信息。

    /// <summary>
    /// Attribute of physical parameters
    /// </summary>
    [Serializable()]
    public class PhysicalUnitTypeAttribute : Attribute, ISerializable
    {

        #region Fields

        static internal readonly Dictionary<Type, PropertyInfo> Properties =
            new Dictionary<Type, PropertyInfo>();


        /// <summary>
        /// Type of angle
        /// </summary>
        private AngleType angleUnit;

        /// <summary>
        /// Type of length
        /// </summary>
        private LengthType lengthUnit;

        /// <summary>
        /// Type of time
        /// </summary>
        private TimeType timeUnit;

        /// <summary>
        /// Type of mass
        /// </summary>
        private MassType massUnit;

        private event Action change = () => { };

        #endregion

        #region Ctor

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="angleType">Type of angle</param>
        /// <param name="lengthType">Type of length</param>
        /// <param name="timeType">Type of time</param>
        /// <param name="massType">Type of mass</param>
        public PhysicalUnitTypeAttribute(AngleType angleType = AngleType.Radian,
            LengthType lengthType = LengthType.Meter,
            TimeType timeType = TimeType.Second,
            MassType massType = MassType.Kilogram)
        {
            this.angleUnit = angleType;
            this.lengthUnit = lengthType;
            this.timeUnit = timeType;
            this.massUnit = massType;
        }

        /// <summary>
        /// Default constructor
        /// </summary>
        public PhysicalUnitTypeAttribute()
        {
            angleUnit = AngleType.Radian;
            lengthUnit = LengthType.Meter;
            timeUnit = TimeType.Second;
            massUnit = MassType.Kilogram;
        }

        /// <summary>
        /// Deserialization constructor
        /// </summary>
        /// <param name="info">Serialization info</param>
        /// <param name="context">Streaming context</param>
        protected PhysicalUnitTypeAttribute(SerializationInfo info, StreamingContext context)
        {
            angleUnit = (AngleType)info.GetValue("AngleType", typeof(AngleType));
            lengthUnit = (LengthType)info.GetValue("LengthType", typeof(LengthType));
            timeUnit = (TimeType)info.GetValue("TimeType", typeof(TimeType));
            massUnit = (MassType)info.GetValue("MassType", typeof(MassType));
        }

        /// <summary>
        /// Constructor
        /// </summary>
        static PhysicalUnitTypeAttribute()
        {
            PropertyInfo[] pi = typeof(PhysicalUnitTypeAttribute).GetProperties();
            foreach (PropertyInfo i in pi)
            {
                Type t = i.PropertyType;
                if (!t.Equals(typeof(object)))
                {
                    Properties[i.PropertyType] = i;
                }
            }
        }


        #endregion

        #region ISerializable Members

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("AngleType", AngleType, typeof(AngleType));
            info.AddValue("LengthType", LengthType, typeof(LengthType));
            info.AddValue("TimeType", TimeType, typeof(TimeType));
            info.AddValue("MassType", MassType, typeof(MassType));
        }

        #endregion

        #region Public

        /// <summary>
        /// Change event
        /// </summary>
        public event Action Change
        {
            add { change += value; }
            remove { change -= value; }
        }


        /// <summary>
        /// Type of angle
        /// </summary>
        public AngleType AngleType
        {
            get
            {
                return angleUnit;
            }
            set
            {
                angleUnit = value;
                change();
            }
        }

        /// <summary>
        /// Type of length
        /// </summary>
        public LengthType LengthType
        {
            get
            {
                return lengthUnit;
            }
            set
            {
                lengthUnit = value;
                change();
            }
        }

        /// <summary>
        /// Type of time
        /// </summary>
        public TimeType TimeType
        {
            get
            {
                return timeUnit;
            }
            set
            {
                timeUnit = value;
                change();
            }
        }

        /// <summary>
        /// Type of mass
        /// </summary>
        public MassType MassType
        {
            get
            {
                return massUnit;
            }
            set
            {
                massUnit = value;
                change();
            }
        }

        #endregion

    }

如果我们有一个具有恒定物理单位的类型,则使用上述类作为属性;否则,它用作以下接口的属性。

     /// <summary>
    /// Holder of attribute of physical parameters
    /// </summary>
    public interface IPhysicalUnitTypeAttribute
    {
        /// <summary>
        /// Attribute of physical parameters
        /// </summary>
        PhysicalUnitTypeAttribute PhysicalUnitTypeAttribute
        {
            get;
            set;
        }
    }

以下字典用于计算系数。

        /// <summary>
        /// Dictionaries which contain coefficients
        /// </summary>
        private static readonly Dictionary<Type, object> dCoefficients = new Dictionary<Type, object>()
       {
           {typeof(AngleType),   new Dictionary<AngleType, double>()
            {
                {AngleType.Radian, 1},
                {AngleType.Degree, 180 / Math.PI},
                {AngleType.Circle, 2 * Math.PI}
            }
            },
           {typeof(LengthType),    new Dictionary<LengthType, double>()
            {
                {LengthType.Meter, 1},
                {LengthType.Kilometer, 1000},
                {LengthType.Centimeter, 0.01}
            }
           },
           {typeof(MassType),   new Dictionary<MassType, double>()
            {
                {MassType.Kilogram, 1},
                {MassType.Gram, 0.001}
            }
           },
           {typeof(TimeType),   new Dictionary<TimeType, double>()
            {
                {TimeType.Day, 1},
                {TimeType.Second, 86400}
            }
            }
       };

这些字典的含义很清楚,以下函数使用这些字典。

          /// <summary>
        /// Coefficient of physical unit
        /// </summary>
        /// <typeparam name="T">From</typeparam>
        /// <param name="source">From unit</param>
        /// <param name="target">To unit</param>
        /// <returns>Coefficient</returns>
        public static double Coefficient<T>(this T source, T target)
        {
            Dictionary<T, double> d = dCoefficients[typeof(T)] as Dictionary<T, double>;
            double kFrom = d[source];
            double kTo = d[target];
            return kTo / kFrom;
        }

这些系数用于更通用的转换,如下所示。

         /// <summary>
        /// Coefficient functions
        /// </summary>
        private static readonly Dictionary<Type, Func<object, object, double>> functions = new Dictionary<Type, Func<object, object, double>>()
        {
             {typeof(AngleType), (object a, object b) =>
                 { return Coefficient<AngleType>((AngleType)a, (AngleType)b);} },
             {typeof(LengthType), (object a, object b) =>
                 { return Coefficient<LengthType>((LengthType)a, (LengthType)b);} },
             {typeof(MassType), (object a, object b) =>
                 { return Coefficient<MassType>((MassType)a, (MassType)b);} },
             {typeof(TimeType), (object a, object b) =>
                 { return Coefficient<TimeType>((TimeType)a, (TimeType)b);} }
        };

        /// <summary>
        /// Gets coefficients
        /// </summary>
        /// <param name="source">Source</param>
        /// <param name="target">Target</param>
        /// <param name="dictionary" />Physical unit dictionary</param>
        /// <returns>Coefficient</returns>
        public static double Coefficient(this PhysicalUnitTypeAttribute source,
            PhysicalUnitTypeAttribute target, Dictionary<Type, int> dictionary)
        {
            if (dictionary == null)
            {
                return 1;
            }
            double a = 1;
            Dictionary<Type, PropertyInfo> p =  PhysicalUnitTypeAttribute.Properties;
            foreach (Type t in dictionary.Keys)
            {
                Func<object, object, double> f = functions[t];
                PropertyInfo pi = p[t];
                object from = pi.GetValue(source);
                object to = pi.GetValue(target);
                double k = f(from, to);
                if (k == 1)
                {
                    continue;
                }
                int m = dictionary[t];
                if (m < 0)
                {
                    m = -m;
                    k = 1.0 / k;
                }
                for (int i = 0; i < m; i++)
                {
                    a *= k;
                }
            }
            return a;
        }

Coefficient 函数的 dictionary 参数,被注释为 物理单位字典,可以通过以下示例轻松解释。 万有引力常数 表示如下。

gravitational constant

以下 物理单位字典 对应于万有引力常数。

         /// <summary>
        /// Gravitational constant physical unit dictionary
        /// </summary>
        private static readonly Dictionary<Type, int> GravityConstUnit =
            new Dictionary<Type, int>()
            {
              {typeof(LengthType), 3},
             {typeof(MassType), -1},
             {typeof(TimeType), -2},
            };

2.3 自动计算

有一组用于自动转换的接口。以下接口用于参数交换。

     /// <summary>
    /// Collection on named data units
    /// </summary>
    public interface IAlias : IAliasBase
    {
        /// <summary>
        /// Names of all data units
        /// </summary>
        IList<string> AliasNames
        {
            get;
        }

        /// <summary>
        /// Access to data unit by name
        /// </summary>
        object this[string name]
        {
            get;
            set;
        }

        /// <summary>
        /// Gets unit type
        /// </summary>
        /// <param name="name">Unit name</param>
        /// <returns>Type of unit</returns>
        object GetType(string name);

        /// <summary>
        /// Change alias event
        /// </summary>
        event Action<IAlias, string> OnChange;

    }

一个对象将参数导出到另一个对象,参数的名称和类型应该一致。如果上述 IAlias 接口被物理单位清单(物理单位字典)扩展,则可以自动进行单位转换。以下接口表示 物理单位字典 的清单。

     /// <summary>
    /// Physical unit dictionary
    /// </summary>
    public interface IPhysicalUnitAlias
    {
        /// <summary>
        /// Gets dictionary of an alias
        /// </summary>
        /// <param name="name">Name</param>
        /// <returns>Physical unit dictionary</returns>
        Dictionary<Type, int> this[string name]
        {
            get;
        }
    }

提供者的 name 参数应与消费者的名称对应。以下函数使用上述接口进行物理参数的自动转换。

         /// <summary>
        /// Conversion of physical units
        /// </summary>
        /// <param name="alias">Alias</param>
        /// <param name="source">Source</param>
        /// <param name="target">Target</param>
        /// <returns>Conversion result</returns>
        public static Dictionary<string, double> ConvertPhysicalUnits
            (this IAlias alias, BaseTypes.Attributes.PhysicalUnitTypeAttribute source,
            BaseTypes.Attributes.PhysicalUnitTypeAttribute target)
        {
            Dictionary<string, double> d = new Dictionary<string, double>();
            BaseTypes.Interfaces.IPhysicalUnitAlias a = alias as
                BaseTypes.Interfaces.IPhysicalUnitAlias;
            IList<string> l = alias.AliasNames;
            foreach (string key in l)
            {
                if (!l.Contains(key))
                {
                    continue;
                }
                object t = alias.GetType(key);
                if (!t.Equals(BaseTypes.FixedTypes.Double))
                {
                    continue;
                }
                double x = (double)alias[key];
                Dictionary<Type, int> dt = a[key];
                if (dt != null)
                {
                    x *=  Coefficient(source,
                        target, dt);
                }
                d[key] = x;
            }
            return d;
        }

上述函数从提供者获取参数,计算转换系数,将参数乘以系数并将结果导出到消费者。

2.4 用户界面。

所有实现 IPhysicalUnitTypeAttribute 接口的对象都有一个清晰统一的用户控件。

User Interface

上述用户控件对应于我源代码中的 UserControlPhysicalUnit 类。

3. 示例

3.1 手动调整物理单位

我对这个任务的描述看起来太长了,但这个例子对某些读者来说有独立的意义。人造地球卫星的运动取决于地球大气层。有一个经验全球性地球大气模型 (NRLMSISE-00) 源代码。然而,这段代码是静态的。我想用它进行多次同时计算,所以我开发了 Msise C++ 类(MSISEAtmosphere 项目)。此类具有独立意义,可以在没有 .NET 的情况下使用。MSISEAtmosphere 项目是 Msise 类的 .NET 包装器。DynamicAtmosphere.MSISE 项目是 MSISEAtmosphere 的 C# 扩展,提供了以下附加功能

  • 物理单位转换;
  • 太阳位置集成计算。

大气参数取决于太阳位置。然而,出于以下原因,我没有将太阳位置计算集成到 MSISEAtmosphere 中。假设用户有自己的太阳位置计算软件。如果我集成我的算法,用户将有两个太阳位置计算算法。太阳位置的计算也是独立的,它包含在 SunPosition 项目中。SunPosition阿尔梅里亚太阳能平台 C++ 项目重构为 C#。太阳位置具有独立意义,阿尔梅里亚太阳能平台 使用它进行太阳能设施。也许我的软件也可以用于太阳能设施,而无需进行大气计算。也许我的软件将用于一项包含两个子任务的任务:太阳能设施和人造地球卫星监测。那么单一的 SunPosition 将用于这两个子任务。DynamicAtmosphere.MSISE.Wrapper 是用于与我的软件集成的下一个扩展。我的软件可以出于不同目的使用此类,例如用于确定人造卫星轨道DynamicAtmosphere.MSISE.Wrapper 包含纯业务逻辑层。因此,它可以在我的Web 项目Windows Forms 项目WPF 项目中使用。DynamicAtmosphere.MSISE.Wrapper.UI 项目提供了以下System.Windows.Forms 用户界面。

OwnUnits

参数选项卡负责空间天气指数 F10.7、Ap、F10.7 平均值。物理单位选项卡负责物理单位。此对象用于卫星的运动方程,其中千米、秒和千克用作物理单位。我们可以选择任何物理单位,此项目的输出应与这些单位对应。

3.2 物理参数自动导出

上述示例涉及手动输入空间天气指数。手动输入无疑对研究任务有用。但对于实时模拟,空间天气指数可以自动通过互联网获取。DynamicAtmosphere.Web 是一个项目,它从http://www.nwra.com/spawx/env_latest.htmlhttp://www.spaceweather.ca/data-donnee/sol_flux/sx-5-mavg-eng.php 获取空间天气指数。DynamicAtmosphere.Web.Wrapper 扩展了 DynamicAtmosphere.Web 以实现与我的框架的互操作性。这两个项目都独立于 MSISE-90 大气模型,因此它们可以与俄罗斯联邦大气模型一起使用。DynamicAtmosphere.Web.Wrapper 的主类型是 DynamicAtmosphere.Web.Wrapper.Atmosphere 类。该类的对象可以是独立的,也可以拥有一个集成的子对象。如果对象是独立的,那么它就像下面显示的那样,是许多消费者的信息提供者。

Many consumers

所有信息消费者应使用相同的物理单位。如果此对象包含集成的子对象,那么它只为单个子对象提供信息。以下两个构造函数解释了这些选项的用法。

         /// <summary>
        /// Constructor of an independent object
        /// </summary>
        public Atmosphere()
        {

        }

        /// <summary>
        /// Constructor with child
        /// </summary>
        /// <param name="childType">Type of child</param>
        public Atmosphere(string childType)
            : this()
        {
            Type t = Type.GetType(childType); // Type of the child object
            child = t.GetConstructor(new Type[0]).Invoke(new object[0]) as IAlias; // Child object
            // Children
            children = new IAssociatedObject[] { child as IAssociatedObject };
            if (child is IAliasConsumer)
            {
                // Adaption of this object by its child
                IAliasConsumer aliasConsumer = child as IAliasConsumer;
                aliasConsumer.Add(this);  // Child object consumes information
            }
        }

因此,child 对象从父对象消费信息。以下代码包含 IAliasConsumerAdd 方法的实现。

         void IAliasConsumer.Add(IAlias alias)
        {
            // ================ Import of parameters ==================
            IAlias al = this;
            List<string> own = al.AliasNames.ToList<string>();
            List<string> external = alias.AliasNames.ToList<string>();
            for (int i = 0; i < external.Count; i++)
            {
                string n = external[i];
                if (dAlias.ContainsKey(n))
                {
                    if (al.GetType(n).Equals(alias.GetType(n)))
                    {
                        al[n] = alias[n];
                    }
                }
            }
            //=============== Export of event handler  ==================
            alias.OnChange += Change;
        }

事件处理程序的导出意味着 Internet 大气参数的变化会强制子参数同时变化。子对象的别名名称与其父对象一致。

         /// <summary>
        /// Names of aliases
        /// </summary>
        private readonly string[] Names = new string[] { "F10_7", "Ap", "F10_7A" };

这些名称是空间天气指数的名称。

上述对象非常特殊,因此应将其用作插件Containers.xml 文件包含插件的清单。

<Root>
  <Assemblies>
    <Assembly file="SunPosition.dll"/>
    <Assembly file="DynamicAtmosphere.MSISE.dll"/>
    <Assembly file="DynamicAtmosphere.MSISE.Wrapper.dll"/>
    <Assembly file="DynamicAtmosphere.MSISE.Wrapper.UI.dll"/>
    <Assembly file="DynamicAtmosphere.Web.dll"/>
    <Assembly file="DynamicAtmosphere.Web.Wrapper.dll"/>
   </Assemblies>
  <Page pageName="Orbital" pageHint="Orbital services">
    <Object icon="Containers\Atmosphere.ico"
           type="DynamicAtmosphere.MSISE.Wrapper.Atmosphere,DynamicAtmosphere.MSISE.Wrapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
           param="" hint="Earth's atmosphere" arrow="false" />
   <Object icon="Containers\AtmosphereWeb.ico"
           type="DynamicAtmosphere.Web.Wrapper.Atmosphere,DynamicAtmosphere.Web.Wrapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
           param="" hint="Earth's atmosphere Web" arrow="false" />
   <Object icon="Containers\AtmosphereWebChild.ico"
           type="DynamicAtmosphere.Web.Wrapper.Atmosphere,DynamicAtmosphere.Web.Wrapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
           param="DynamicAtmosphere.MSISE.Wrapper.Atmosphere,DynamicAtmosphere.MSISE.Wrapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
          hint="Earth's atmosphere Web + child" arrow="false" />
   </Page>
 </Root>

任何 Object 标签都对应一个插件对象。下表解释了上述 XML 代码。

N对象创建注释
1new DynamicAtmosphere.MSISE.Wrapper.Atmosphere()MSISE 大气模型
2new DynamicAtmosphere.Web.Wrapper.Atmosphere()来自 Web 的大气参数
3new DynamicAtmosphere.Web.Wrapper.Atmosphere(new DynamicAtmosphere.MSISE.Wrapper.Atmosphere())来自 Web 的大气参数 + MSISE 大气模型

下图显示了这些对象。

Atmosphere

如果Web atmosphere 包含一个集成的子对象,则编辑器窗体将包含一个附加的选项卡。以下两张图片显示了Web atmosphere 带有子对象和不带子对象的属性。子对象仅导入空间天气指数,子对象的输出物理单位取决于设置。

ChildWithout child

3.3 自动导出和物理单位转换

存在开普勒轨道预测算法两行根数集 (TLE) 是用于传递描述地球轨道卫星轨道轨道根数的集合的数据格式。这两个对象可以聚合为一个对象,或独立使用。例如,开普勒轨道预测算法可用于模拟恒星运动。两行根数集 (TLE) 可用于更精确的轨道预测方法(参见此处)。我开发了专门的软件来提取NORAD 两行根数集当前数据。该软件包含 3 个项目。第一个项目 Celestrak.NORAD.Satellites 只包含业务逻辑。该项目的主类如下所示。

     /// <summary>
    /// Data of satellite
    /// </summary>
    [Serializable()]
    [PhysicalUnitType(AngleType = AngleType.Degree, LengthType = LengthType.Meter,
        MassType = MassType.Kilogram, TimeType = TimeType.Day)]
    public class SatelliteData : CategoryObject, IChildrenObject, IMeasurements, IPropertiesEditor,
        ISeparatedAssemblyEditedObject, IAlias, ISerializable, IPhysicalUnitAlias, IEventHandler

PhysicalUnitType(AngleType = AngleType.Degree, LengthType = LengthType.Meter, MassType = MassType.Kilogram, TimeType = TimeType.Day) 表示该类型使用了固定的物理单位。以下代码包含 IAliasIPhysicalUnitAlias 的实现。

         /// <summary>
        /// Physical unit dictionary
        /// </summary>
        internal static readonly Dictionary<string, Dictionary<Type, int>> AliasNames =
         new Dictionary<string, Dictionary<Type, int>>()
       {
            {"Eccentricity", null},
            {"Inclination", new Dictionary<Type, int>(){{typeof(AngleType), 1}}},
            {"Ascending Node",  new Dictionary<Type, int>(){{typeof(AngleType), 1}}},
            {"Argument Of Periapsis",  new Dictionary<Type, int>(){{typeof(AngleType), 1}}},
            {"Mean Anomaly At Epoch",  new Dictionary<Type, int>(){{typeof(AngleType), 1}}},
            {"Mean Motion", new Dictionary<Type, int>{{typeof(AngleType), 1}, {typeof(TimeType), -1}}},
            {"FD MeanMotion", null},
            {"SD MeanMotion", null},
            {"Perturbation", null},
            {"Mass", new Dictionary<Type, int>(){{typeof(MassType), 1}}},
            {"Epoch",  null}
        };


       #region IPhysicalUnitAlias Members

        Dictionary<Type, int> IPhysicalUnitAlias.this[string name]
        {
            get
            {
                if (AliasNames.ContainsKey(name))
                {
                    return AliasNames[name];
                }
                return null;
            }
        }

       #endregion

        #region IAlias Members

        IList<string> IAlias.AliasNames
        {
            get { return AliasNames.Keys.ToList<string>(); }
        }

        object IAlias.this[string name]
        {
            get
            {
                return aliases[name];
            }
            set
            {
            }
        }

        object IAlias.GetType(string name)
        {
            if (name.Equals("Epoch"))
            {
              return  FixedTypes.DateTime;
            }
            return FixedTypes.Double;
        }


        event Action<IAlias, string> IAlias.OnChange
        {
            add { onChange += value; }
            remove { onChange -= value; }
        }

        #endregion

AliasNames 代表物理单位字典Celestrak.NORAD.Satellites.Wpf.UI 项目提供了 WPF 用户界面,该界面用于 WPF 和 System.Windows.Forms 应用程序。Celestrak.NORAD.Satellites.UI 包含一个 System.Windows.Forms 用户界面。与DynamicAtmosphere.Web.Wrapper.Atmosphere 一样,此类数据可以导出到其集成的子对象。 开普勒轨道预测算法可用作子对象。开普勒轨道预测算法实现在 Celestia. 空间实时三维可视化项目中,我为其开发了 C# 版本。CelestialMechanics 项目包含完全独立的算法版本。CelestialMechanics.Wrapper 用于与我的框架兼容。CelestialMechanics.Wrapper.Classes.Orbit 类中的别名名称与 Celestrak.NORAD.Satellites.SatelliteData 中的名称一致。由于 Celestrak.NORAD.Satellites.SatelliteData 实现了 IPhysicalUnitAlias 接口,因此除了数据导出外,它还实现了物理单位的自动转换。 ConvertPhysicalUnits 函数用于此目的。下图包含三个对象。

3 Orbital

下表解释了这些对象。

N名称对象创建注释
1NORADnew Celestrak.NORAD.Satellites.SatelliteData()NORAD 数据
2轨道new CelestialMechanics.Wrapper.Classes.Orbit()开普勒轨道预测算法
3NORAD + 轨道new Celestrak.NORAD.Satellites.SatelliteData(new CelestialMechanics.Wrapper.Classes.Orbit())NORAD 数据 + 开普勒轨道预测算法

下图显示了NORAD 对象的用户界面。

Data 1Data 2

上述界面清晰明了,解释了业务逻辑。下图显示了Orbital 对象的用户界面。

Satellite 1Satellite 2

上述用户界面包含物理单位编辑器。下图显示了NORAD + Orbital 对象的属性。

NORAD + OrbitalNORAD + Orbital

NORAD + OrbitalNORAD + Orbital

最后两张图片包含子对象的属性。轨道参数取决于父对象,即它们与所选卫星的参数一致。因此,这些参数不可编辑。如果子对象不依赖于父对象,则轨道参数是可编辑的。但是,如果我们更改物理单位,数值将会改变,如下所示。

NORAD + OrbitalNORAD + Orbital

关注点

有时物理单位的转换比工程任务的其他部分更复杂。

历史

我曾尝试手动将 MSISE-90 的 Fortran 版本转换为 C++。我认为该模型代码对其开发者来说并不清晰。我的尝试失败了。然后我找到了 f2c 将 Fortran 77 转换为 C 代码。但我发现了一个错误。同一个函数调用两次会产生不同的结果。然后我找到了 MSISE-90 的 C 代码。这段代码也不清晰。我的同事告诉我,航空航天领域有很多不清晰的 Fortran 代码。然后我问自己:

  • 我自己的代码是否清晰?
  • 我能让自己的代码清晰吗?

我翻译了 Celestia. 空间实时三维可视化,发现该项目包含以下代码。

const double astro::G = 6.672e-11; // N m^2 / kg^2
(见此处),然而目前重力常数的值为 6.674 28 (+/- 0.000 67) x 10-11 m3 kg-1 s -2

阅读更多:http://www.universetoday.com/43227/gravity-constant/#ixzz2r7kVBVH5

这一事实启发我修改自己的代码。现在我的地球引力场模型可以自动更新。我的新引力场的用户界面如下所示。

Gravity

上图表示引力场模型的参数存储在 http://mathframe.com/databases/gravity/GEM-T3.FLD 文件中。

© . All rights reserved.