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/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容