SpaceDSL天体动力学仿真库的介绍、编译和使用说明

1. 介绍

SpaceDSL是一个天体动力学仿真库。它使用C++编写,为天体动力学爱好者提供一个开放的框架以更自由的方式实现天体动力学仿真。本项目基于MIT协议开放源码,以供自由使用。本项目通过CMake构建,可以用于WindowsLinuxMac OSSpaceDSL库可以被编译成静态库、动态库和Python依赖库。当然也支持直接使用。

1.1 核心特性

SpaceDSL包含了有关天体动力学仿真的全部基本功能,包括:

  • 天文时间系统:支持EOP web Service,包含UTC、UT1和TT等多种时间系统的定义和转换
  • 参考坐标系:包含ECI、TOD、ECEF、VVLH等常用空间坐标系的变换方程
  • JPL星历:重新打包了JPL星历读取模块,提供最新的DE436文件,包括1950至2050年间的数据
  • 地球重力模型:使用EGM2008数据(80X80)和球谐函数构建地球的高精度重力模型
  • 其他摄动模型:大气阻力(NRLMSISE2000)、太阳辐射压、第三天体重力(Third Body Gravity)
  • 双天体轨道预测、J2轨道预测和用于航天器的高精度轨道预测
  • 多种地面目标模型和访问分析(Access Analysis
  • 传感器支持(Simple ConicRectangular
  • 常用物理常量
  • 多线程并行支持:类似于Qt的API,包含线程和线程池
  • 支持基于STL的异常处理
  • 提供基于NLopt的非线性优化库
  • 提供基于ElectronCesium的可视化工具

1.2 后续支持的特性

  • 摄动模型:固体潮(Earth Tide)、相对论效应
  • 航天器的相对运动仿真
  • 轨道动作仿真特性
  • 轨道偏移量预测

2. 编译

2.1 支持的编译器

  • Clang/LLVM 3.3 及以上版本(如果是Xcode的Clang,需要5.0.0及以上版本)
  • GCC 7.2 及以上版本
  • Microsoft Visual Studio 2015 Update 3 及以上版本
  • Intel C++ compiler 16 及以上版本

2.2 编译过程

克隆项目代码:

git clone https://github.com/Astrodynamics/SpaceDSL.git

使用CLion打开项目:


选择Build All
image

注意,如果平台是Linux系统,则在Build之前需要安装以下依赖:(以Ubuntu 16.04系统为例,其他Linux系统下的安装指令类似):

sudo apt-get install python-dev

sudo apt-get install python3-dev

选择Run->Build编译全部

编译成功后,文件中多出了Build文件夹,其中astrodata是该库需要的一些基础数据文件,libNLOpt_d.dyliblibSpaceDSL_d.0.0.dylib等是动态链接库文件,PySpaceDSL_d.cpython-37m-darwin.so是该项目使用python封装后的依赖库文件。

基于以上动态链接库和位于Build/Dependence文件夹下的头文件,即可编写C++代码,进行仿真,示例代码如下:(TestMain.cpp)

#include <iostream>

#include "SpaceDSL/SpaceDSL.h"

using namespace std;
using namespace SpaceDSL;

int main(int argc, char *argv[])
{
    cout<<"SpaceDSL Test Run!"<<endl;
    try
    {
        /// Initial Data
        UTCCalTime vehicle_epoch     (2018,1,4,16,58,11.1);

        string targetName1 = "Facility1";
        PointTarget target1(targetName1, -75.5966*DegToRad, 40.0386*DegToRad, 0, 10*DegToRad);

        string vehicle_name1 = "The First Vehicle";// h = 257km
        CartState vehicle1_cart0(-5.04649e+06, -3.53951e+06, -2.44795e+06,
                                    4954.67 , -4008.83, -4417.73 );
        double vehicle1_mass = 1000.0;

        string vehicle_name2 = "The Second Vehicle"; // h = 1065km
        CartState vehicle2_cart0(-5.65484e+06, -3.96619e+06, -2.74305e+06,
                                    4680.57 , -3787.06, -4173.34 );
        double vehicle2_mass = 1500.0;

        /// Mission Start
        Mission *pMission = new Mission();
        auto pVehicle1 = pMission->InsertSpaceVehicle(vehicle_name1,vehicle_epoch,vehicle1_cart0,vehicle1_mass, 2.2, 3, 1.0, 3);
        auto pVehicle2 = pMission->InsertSpaceVehicle(vehicle_name2,vehicle_epoch,vehicle2_cart0,vehicle2_mass, 2.2, 6, 1.0, 6);
        pMission->RemoveSpaceVehicle(pVehicle2->GetID());
        pMission->InsertFacility(targetName1,-75.5966*DegToRad, 40.0386*DegToRad, 0, 10*DegToRad);
        ThirdBodyGravitySign thirdGravSign;
        thirdGravSign.bIsUseSunGrav = true;
        thirdGravSign.bIsUseMoonGrav = true;
        double kp = 3.0;
        VectorXd ap;
        ap.resize(7);
        ap.fill(0.0);
        ap(0) = GeomagneticKpToAp(kp);
        pMission->SetEnvironment(E_Earth, GravityModel::GravModelType::E_EGM08Model,
                                 20 , 20, thirdGravSign,
                                 GeodeticCoordSystem::GeodeticCoordType::E_WGS84System,
                                AtmosphereModel::AtmosphereModelType::E_NRLMSISE00Atmosphere,
                                 150,150,ap,
                                 true, true);
        pMission->SetPropagator(E_RungeKutta4, 60);
        //pMission->SetPropagator(E_RungeKutta78, 60, 0.01, 1, 120, 100);
        UTCCalTime initial_time     (2018,1,5,16,58,11.1);
        pMission->SetMissionSequence(initial_time, 86123);
        pMission->Start(true);

        cout<<"------First Calculation Finished ------"<<endl;
        pMission->CalMissionAccessData();
        auto accessListMap = pMission->GetAccessData();
        for (auto iterMap = accessListMap->begin();
             iterMap != accessListMap->end();
             ++iterMap)
        {
            cout<<"Access Data:"<<endl;
            cout<<iterMap->first.first->GetName()<<"--------"<<iterMap->first.second->GetName()<<endl;
            cout<<"  Start Time (UTCG)           Stop Time (UTCG)    Duration (sec)"<<endl;
            auto accessList = iterMap->second;
            for(auto &data:accessList)
            {
                double mjd = CalendarTimeToMjd(data.first);
                cout.precision(15);
                cout<<mjd<<"    "<<data.first.ToString()<<"    "<<data.second.ToString()<<"    "<<(data.second - data.first)<<endl;
            }
        }

        pVehicle1->Reset();
        pMission->ClearProcessData();
        pMission->Start();

        pMission->CalMissionAccessData();
        cout<<"------Second Calculation Finished ------"<<endl;
        accessListMap = pMission->GetAccessData();
        for (auto iterMap = accessListMap->begin();
             iterMap != accessListMap->end();
             ++iterMap)
        {
            cout<<"Access Data:"<<endl;
            cout<<iterMap->first.first->GetName()<<"--------"<<iterMap->first.second->GetName()<<endl;
            cout<<"  Start Time (UTCG)           Stop Time (UTCG)    Duration (sec)"<<endl;
            auto accessList = iterMap->second;
            for(auto &data:accessList)
            {
                double mjd = CalendarTimeToMjd(data.first);
                cout.precision(15);
                cout<<mjd<<"    "<<data.first.ToString()<<"    "<<data.second.ToString()<<"    "<<(data.second - data.first)<<endl;
            }
        }

        //CalObservationAll();

        cout<<"Calculation Finished!"<<endl;

        /// CZML File Wirte;
        CZMLScript  script;
        script.Initializer("TestData.czml", pMission);
        script.WirteCZML();
        cout<<"CZML Output Finished!"<<endl;
        pMission->Destory();

    }
    catch (SPException &e)
    {
        e.what();
    }

    return 0;
}

通过Python封装过的依赖库PySpaceDSL,可以使用Python编写仿真代码。
PySpaceDSL_d.cpython-37m-darwin.so文件重命名为PySpaceDSL.so,同时在当前路径下放置astrodata基础数据文件夹,编写Python脚本(TestPython.py):

from PySpaceDSL import *
import numpy as np

print("SpaceDSL Test Run!")


def main():
    # Initial Data
    initial_time = UTCCalTime(2018, 1, 4, 16, 58, 11.1)

    vehicle1_cart0 = CartState(-5.04649e+06, -3.53951e+06, -2.44795e+06, 4954.67, -4008.83, -4417.73)
    vehicle1_mass = 1000.0

    vehicle2_cart0 = CartState(-5.65484e+06, -3.96619e+06, -2.74305e+06, 4680.57, -3787.06, -4173.34)
    vehicle2_mass = 1500.0
    # Mission Start
    test_mission = Mission()
    test_mission.InsertSpaceVehicle('The First Vehicle', initial_time, vehicle1_cart0, vehicle1_mass, 2.2, 3, 1.0, 3)
    test_mission.InsertSpaceVehicle('The Second Vehicle', initial_time, vehicle2_cart0, vehicle2_mass, 2.2, 6, 1.0, 6)
    test_mission.InsertFacility('Facility1', -75.5966 * DegToRad(), 40.0386 * DegToRad(), 0, 10 * DegToRad())
    thirdGravSign = ThirdBodyGravitySign()
    thirdGravSign.bIsUseSunGrav = True
    thirdGravSign.bIsUseMoonGrav = True
    kp = 3.0
    ap = np.zeros(7)
    ap[0] = GeomagneticKpToAp(kp)

    test_mission.SetEnvironment(SolarSysStarType.E_Earth, GravityModel.GravModelType.E_EGM08Model, 20, 20,
                                thirdGravSign, GeodeticCoordSystem.GeodeticCoordType.E_WGS84System,
                                AtmosphereModel.AtmosphereModelType.E_NRLMSISE00Atmosphere,
                                150, 150, ap, True, True)
    test_mission.SetPropagator(IntegMethodType.E_RungeKutta4, 60.0)
    test_mission.SetMissionSequence(initial_time, 86400)
    test_mission.Start(True)

    print('------First Calculation Finished ------')
    test_mission.CalMissionAccessData()
    accessListMap = test_mission.GetAccessData()
    print(accessListMap)

    # CZML File Wirte;
    script = CZMLScript()
    script.Initializer("PyTestData.czml", test_mission)
    script.WirteCZML()
    print("CZML Output Finished!")


if __name__ == "__main__":
    main()

运行程序,会在当前目录生成一个.CZML后缀的文件。CMZL文件是一种用来描述动态场景的JSON架构的语言,主要用于Cesium在浏览器中的展示。这里的CZML文件就是用于可视化展示仿真结果的描述文件。

3.使用说明

编写C++程序或Python脚本完成仿真过程,并自动生成.CZML文件后,可以通过SpaceDSL自带的可视化程序ElectronVisualizer展示仿真结果。

首先需要在系统安装Node.js环境。
然后切换到SpaceDSL项目中的ElectronVisualizer路径下:

cd ElectronVisualizer

安装相关依赖库:

npm install --save-dev electron

npm install --save-dev cesium

npm install --save glob

然后,启动可视化软件:

npm start

软件启动后,点击菜单Read Script,选择先前生成的.CZML文件加载。

image

文件加载后,操作界面左下角的控制按钮,即可播放仿真结果。

原文链接:http://www.trojx.me/2020/01/08/spacedsl/

推荐阅读更多精彩内容