物理单位的自动转换






4.85/5 (4投票s)
有用链接
- 通用工程软件主页
- 原文
- 单位转换
- 计量单位
- 物理单位
- NORAD 两行根数集
- Celestia. 空间实时三维可视化
- 从地面到太空的地球大气经验全球模型 (NRLMSISE-00) 源代码
- 弹道实验室
- 阿尔梅里亚太阳能平台
1 简介。
任何高级软件都包含第三方软件。通常第三方软件需要适应自有软件。不同的软件可能使用不同的物理单位。例如,从地面到太空的地球大气经验全球模型 (NRLMSISE-00) 源代码对于大气物理学研究非常方便,但对于弹道学则不方便,因为弹道学使用其他物理单位。物理单位的转换是一项非常重要的任务。
++++++++++++++++++++++
统一单位重要性的一個例子是 NASA 的 火星气候轨道器 任务的失败,该任务于 1999 年 9 月在前往火星的任务中意外被摧毁,未能进入轨道,原因是关于力的单位存在沟通失误:不同的计算机程序使用了不同的测量单位(牛顿 与 磅力)。大量的努力、时间和金钱被浪费了。[6][7]
1999 年 4 月 15 日,大韩航空货运6316 次航班 从上海飞往首尔的航班因机组人员混淆塔台指令(以米为单位)和高度计读数(以英尺为单位)而失事。造成三名机组人员和地面五人死亡,三十七人受伤。[8][9]
1983 年,一架波音 767(后来被称为金梅冰川滑翔机)由于在计算加拿大航空公司第一架使用公制单位的飞机的燃油供应时出现两次错误,导致飞机在飞行途中燃油耗尽。[10] 这起事故显然是由于同时使用公制和英制单位以及体积和质量单位的混淆所致。
摘自这里。
++++++++++++++++++++
有时物理单位的转换需要大量工作,但这项工作可以部分或完全自动化。本文致力于物理单位自动化问题。我的文章包含很多细节,因为我的一些模块可能会引起一些读者的兴趣。本文也可以看作是关于低内聚的实践指南。
2 背景
互联网上有很多有用的信息。然而,通常这些信息需要根据自己的目的进行调整。本文致力于物理单位的自动转换。如果我们拥有信息的提供者和消费者
并且消费者的物理单位与提供者的不同,那么我们就需要进行单位转换。我的软件可以部分或完全自动地执行此操作。
2.1 理论问题
理论问题在此解释,以下公式表示转换系数的对数。
.
我使用了上述公式的指数版本。
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 参数,被注释为 物理单位字典,可以通过以下示例轻松解释。 万有引力常数 表示如下。
以下 物理单位字典 对应于万有引力常数。
/// <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
接口的对象都有一个清晰统一的用户控件。
上述用户控件对应于我源代码中的 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 用户界面。
参数选项卡负责空间天气指数 F10.7、Ap、F10.7 平均值。物理单位选项卡负责物理单位。此对象用于卫星的运动方程,其中千米、秒和千克用作物理单位。我们可以选择任何物理单位,此项目的输出应与这些单位对应。
3.2 物理参数自动导出
上述示例涉及手动输入空间天气指数。手动输入无疑对研究任务有用。但对于实时模拟,空间天气指数可以自动通过互联网获取。DynamicAtmosphere.Web
是一个项目,它从http://www.nwra.com/spawx/env_latest.html 和http://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
类。该类的对象可以是独立的,也可以拥有一个集成的子对象。如果对象是独立的,那么它就像下面显示的那样,是许多消费者的信息提供者。
所有信息消费者应使用相同的物理单位。如果此对象包含集成的子对象,那么它只为单个子对象提供信息。以下两个构造函数解释了这些选项的用法。
/// <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
对象从父对象消费信息。以下代码包含 IAliasConsumer
的 Add
方法的实现。
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 | 对象创建 | 注释 |
1 | new DynamicAtmosphere.MSISE.Wrapper.Atmosphere() | MSISE 大气模型 |
2 | new DynamicAtmosphere.Web.Wrapper.Atmosphere() | 来自 Web 的大气参数 |
3 | new DynamicAtmosphere.Web.Wrapper.Atmosphere(new DynamicAtmosphere.MSISE.Wrapper.Atmosphere()) | 来自 Web 的大气参数 + MSISE 大气模型 |
下图显示了这些对象。
如果Web atmosphere 包含一个集成的子对象,则编辑器窗体将包含一个附加的选项卡。以下两张图片显示了Web atmosphere 带有子对象和不带子对象的属性。子对象仅导入空间天气指数,子对象的输出物理单位取决于设置。
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)
表示该类型使用了固定的物理单位。以下代码包含 IAlias
和 IPhysicalUnitAlias
的实现。
/// <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 函数用于此目的。下图包含三个对象。
下表解释了这些对象。
N | 名称 | 对象创建 | 注释 |
1 | NORAD | new Celestrak.NORAD.Satellites.SatelliteData() | NORAD 数据 |
2 | 轨道 | new CelestialMechanics.Wrapper.Classes.Orbit() | 开普勒轨道预测算法 |
3 | NORAD + 轨道 | new Celestrak.NORAD.Satellites.SatelliteData(new CelestialMechanics.Wrapper.Classes.Orbit()) | NORAD 数据 + 开普勒轨道预测算法 |
下图显示了NORAD 对象的用户界面。
上述界面清晰明了,解释了业务逻辑。下图显示了Orbital 对象的用户界面。
上述用户界面包含物理单位编辑器。下图显示了NORAD + 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
这一事实启发我修改自己的代码。现在我的地球引力场模型可以自动更新。我的新引力场的用户界面如下所示。
上图表示引力场模型的参数存储在 http://mathframe.com/databases/gravity/GEM-T3.FLD 文件中。