STK与VC++联合编程实战(第三回:加入卫星对象)
特别声明,本人对于天体物理学、轨道动力学完全是门外汉,不是一个学科方向,本人仅从代码角度以及STK提供的代码和资料作为参考进行分析,欢迎专业人士指正。若不喜,请勿喷!
继续以STK提供的VC++代码实例Events项目为例分析。
加入卫星的代码如下(Helper源文件中,自己增加了注释):
void CObjectModelHelper::CreateSatellite(STKObjects::IAgStkObjectRootPtr pRoot) { static int iNext = 0; char buf[255]; double aporad, perrad; _bstr_t bstrName; IAgOrbitStateClassicalPtr pClassical; IAgStkObjectPtr pNewObj; // STK Object IAgSatellitePtr pSat; // STK卫星对象 IAgVePropagatorTwoBodyPtr pTwoBodyProp; // 二体轨道预报器 IAgClassicalSizeShapeRadiusPtr pRadius; // Build the satellite name itoa(iNext++, buf, 10); bstrName = "Satellite"; bstrName += buf; // 确保首先执行了 NewScenario 操作 ASSERT(pRoot != NULL); // Add a new instance of the Satellite to the scenario // eSatellite在文件agstkobjects.tlh中定义,表示STK中的卫星对象 //enum AgESTKObjectType //{ // ... = 17, // eSatellite = 18, // ... = 19, //}; // 注:本例中的绝大部分STK对象都是在agstkobjects.tlh/.tli文件中声明的(原型) // IAgStkObjectRootPtr pRoot,此为STK应用中所有对象的ROOT(根) // IAgStkObjectPtr IAgStkObjectRoot::GetCurrentScenario(),通过根对象得到当前的场景对象 // IAgStkObjectCollectionPtr IAgStkObject::GetChildren(),通过当前场景对象得到对象集合(object collection) // IAgStkObjectPtr IAgStkObjectCollection::New(enum AgESTKObjectType EClassType, _bstr_t InstName),通过对象集合新建一个对象 // 执行对象创建的是接口 IAgStkObjectCollection(即,场景的对象集合) pNewObj = pRoot->GetCurrentScenario()->GetChildren()->New(eSatellite, bstrName); // 下面的赋值应当在确定新建对象确实与等号左侧对象为同一类型 pSat = pNewObj; // Set the propagator type // 设置轨道预报器:ePropagatorTwoBody,STK给的对外接口中定义了 15 种轨道预报器 pSat->SetPropagatorType( ePropagatorTwoBody ); // 赋值,pSat->Propagator(IAgVePropagatorPtr Propagator;) // 可以将 IAgVePropagatorPtr 类型的接口指针赋值给 IAgVePropagatorTwoBodyPtr 类型的接口指针? // 类似于前面的赋值语句:pSat = pNewObj; pTwoBodyProp = pSat->Propagator; // Get the initial state's classical representation // IAgOrbitStateClassical pClassical;,经典轨道参数? // IAgVeInitialStatePtr InitialState;,轨道初始状态 // STKUtil::IAgOrbitStatePtr Representation;,轨道状态表示? // IAgOrbitStatePtr IAgOrbitState::ConvertTo(enum AgEOrbitStateType Type),转换为经典轨道参数状态? pClassical = pTwoBodyProp->InitialState->Representation->ConvertTo(eOrbitStateClassical); // 以大小来描述轨道形状,其他的还有:轨道高度、半长轴、轨道周期、平均运动(MeanMotion)等 pClassical->SizeShapeType = eSizeShapeRadius; // IAgClassicalSizeShapePtr SizeShape; pRadius = pClassical->SizeShape ; // Set up the orbit's initial state // 设置卫星的轨道初始状态 // 顾名思义:aporad,远地点;perrad,近地点。根据实际值,变量应当命名为apogee和perigee更合适? // 按理 aporad 需要大于 perrad,随机函数如何保证的呢?或许无所谓,系统会自动处理? aporad = rand() % 12000; // 相当于最大远地点为 12000km perrad = rand() % 12000; pRadius->ApogeeRadius = 6356.75231424 + aporad; pRadius->PerigeeRadius = 6356.75231424 + perrad; // 轨道倾角 pClassical->Orientation->Inclination = rand() % 180; // Assign the orbit state // 设置轨道初始状态,就上面的计算来看,仅指定了三个参数:近地点、远地点、轨道倾角; // 根据近地点和远地点可以计算轨道离心率,轨道六根数还差三个?其他三个参数都是默认值 // 其他三个参数为:RAAN,近日点幅角,指定历元的平近点角 // 其他的参数都默认了,所以在界面上不停增加卫星,会发现卫星的 RAAN 都在一个点上, // 视觉上初始状态时卫星可以在空间连成一条线! pTwoBodyProp->InitialState->Representation->Assign( pClassical ); // Build the satellite's orbit // 执行轨道计算(预报器计算,并显示) pTwoBodyProp->Propagate(); } |
流程大致分析:
- 在当前场景中首先增加一个卫星对象(注:此时只是增加了一个卫星对象,在没有指定卫星的轨道预报器(Orbit Propagator)并根据轨道预报器类型初始化轨道参数之前,三维场景并不会绘制卫星状态,也绘制不出来,这与其他类型的对象不同,也可以通过STK程序操作验证)。
- 获取当前场景,获取当前场景的对象为pRoot(个人理解其代表了一个独立运行的STK应用程序/进程)。
- 由场景对象获取当前场景的对象集合(IAgStkObjectCollection),这个集合应该是包含了场景中的所有对象,不出例外的话是一个树型结构。
- 由(场景)对象集合创建一个新的对象,即本例中new一个卫星对象。
- 将新建的对象(StkObject)赋值给卫星对象(Satellite),以便进行后续针对卫星类型对象的初始化操作。
- 指定卫星的轨道预报器类型,本例中为二体轨道预报器(Two Body),后面接着需要指定的轨道预报器进行不同的初始状态设置。
- 将当前预报器的初始状态表示转换为经典轨道状态表示,这是针对二体轨道预报器的操作,不知道其他类型的轨道预报器该如何操作,下一步继续探索!
- 对经典轨道状态初始化,包括近地点、远地点、轨道倾角,其他的轨道参数保持了默认值。
- 将设置后的轨道数据赋值给当前卫星对象的轨道预报器(…->Assign(pClassical))。
- 由轨道预报器执行轨道计算。(计算完毕后,场景会自动更新)
下面通过指定二体轨道预报器的其他轨道参数,以升交点赤经(RAAN)为例探索一下……
示例代码中是通过如下的赋值初始化轨道参数的:
pTwoBodyProp->InitialState->Representation->Assign( pClassical ); |
顺腾摸瓜:pTwoBodyProp(即,IAgVePropagatorTwoBody)
IAgVePropagatorTwoBodyPtr pTwoBodyProp; // pTwoBodyProp 是IAgVePropagatorTwoBody类型 IAgVePropagatorTwoBody : IAgVePropagator // IAgVePropagator : IUnknown { // 属性 _variant_t StartTime; _variant_t StopTime; double Step; IAgVeInitialStatePtr InitialState; IAgVeHPOPForceModelPtr ForceModel; IAgVeIntegratorPtr Integrator; IAgVeCovariancePtr Covariance; // 方法 HRESULT Propagate ( ); _variant_t GetStartTime ( ); void PutStartTime (const _variant_t & pVal ); _variant_t GetStopTime ( ); void PutStopTime (const _variant_t & pVal ); double GetStep ( ); void PutStep (double pVal ); IAgVeInitialStatePtr GetInitialState ( ); IAgVeHPOPForceModelPtr GetForceModel ( ); IAgVeIntegratorPtr GetIntegrator ( ); IAgVeCovariancePtr GetCovariance ( ); } |
可以看出轨道预报器的基类(IAgVePropagator)对外提供的设置接口(Put接口)包括:
- 轨道计算(Propagate());
- 设置开始时间(PutStartTime());
- 结束时间(PutStopTime());
- 计算步长(PutStep())。
IAgVePropagatorTwoBody : IAgVePropagator { // 属性(忽略了继承自父类的相关属性) VARIANT_BOOL UseScenarioAnalysisTime; // 是否使用场景中的分析时间,通常均为true // 方法(忽略了父类已定义/提供的方法) VARIANT_BOOL GetUseScenarioAnalysisTime ( ); void PutUseScenarioAnalysisTime (VARIANT_BOOL pRetVal ); }; |
可以看出,二体轨道预报器只是增加了一个‘是否使用场景的分析时间’的属性,按理其他轨道预报器也都有这个参数,为啥不定义到父类?
顺腾摸瓜:pTwoBodyProp->InitialState(即,IAgVeInitialState)
IAgVeInitialState : IUnknown { // 属性 _variant_t Epoch; STKUtil::IAgOrbitStatePtr Representation; enum AgEVePropagationFrame PropagationFrame; SAFEARRAY * SupportedPropagationFrames; // 接口方法 _variant_t GetEpoch ( ); void PutEpoch (const _variant_t & pVal ); STKUtil::IAgOrbitStatePtr GetRepresentation ( ); enum AgEVePropagationFrame GetPropagationFrame ( ); void PutPropagationFrame (enum AgEVePropagationFrame pVal ); SAFEARRAY * GetSupportedPropagationFrames ( ); }; |
接口类IAgVeInitialState有一个Epoch属性,应当是跟发射时间有关,另外一个重要属性是STKUtil::IAgOrbitStatePtr Representation,根据名称猜测是轨道状态,继续深挖。
顺藤摸瓜:pTwoBodyProp->InitialState->Representation(即,IAgOrbitState)
IAgOrbitState : IUnknown // 轨道状态表示 { // 属性 enum AgEOrbitStateType OrbitStateType; _bstr_t CentralBodyName; _variant_t Epoch; // 接口方法 IAgOrbitStatePtr ConvertTo (enum AgEOrbitStateType Type ); // 轨道状态类型预定义了6种 // eOrbitStateCartesian = 0, -- 笛卡尔 // eOrbitStateClassical = 1, -- 经典 // eOrbitStateEquinoctial = 2, -- 天球赤道 // eOrbitStateDelaunay = 3, -- 洛尼? // eOrbitStateSpherical = 4, -- 球面坐标系 // eOrbitStateMixedSpherical = 5, -- 混合球面 // eOrbitStateGeodetic = 6 -- 大地测量 enum AgEOrbitStateType GetOrbitStateType ( ); // Assign()方法使得可以设置轨道初始状态 HRESULT Assign (struct IAgOrbitState * pOrbitState ); HRESULT AssignClassical (// 经典表示:半长轴、偏析率、倾角、近地点幅角、RAAN enum AgECoordinateSystem ECoordinateSystem, double SemiMajorAxis, Eccentricity, Inclination, ArgOfPerigee, RAAN, MeanAnomaly ); HRESULT AssignCartesian (// 笛卡尔坐标表示法 enum AgECoordinateSystem ECoordinateSystem, double XPosition, YPosition, ZPosition, XVelocity, YVelocity, ZVelocity ); HRESULT AssignGeodetic (// 大地测量表示法:经纬高、经纬高速度 enum AgECoordinateSystem ECoordinateSystem, double Latitude, Longitude, Altitude, LatitudeRate, LongitudeRate, AltitudeRate ); HRESULT AssignEquinoctial (// 天球赤道表示法? enum AgECoordinateSystem ECoordinateSystem, double SemiMajorAxis, H, K, P, Q, MeanLon, enum AgEEquinoctialFormulation EquinoctialFormulation ); HRESULT AssignMixedSpherical (// 混合球面(坐标)表示法? enum AgECoordinateSystem ECoordinateSystem, double Latitude, Longitude, Altitude, HorFlightPathAngle, FlightPathAzimuth, Velocity ); HRESULT AssignSpherical (// 球面(坐标)表示法? enum AgECoordinateSystem ECoordinateSystem, double Latitude, Longitude, Radius, HorFlightPathAngle, FlightPathAzimuth, Velocity ); _bstr_t GetCentralBodyName ( ); _variant_t GetEpoch ( ); void PutEpoch (const _variant_t & pRetVal ); }; |
故,想要指定升交点赤经(RAAN),需要指定轨道坐标系为经典(Classical)并需要找到设置RAAN的接口方法,并通过方法AssignClassical()来完成设置(实际是通过Assign()方法来完成的),Assign()方法接受的参数为IAgOrbitState,则可以通过设置输入参数中的RAAN来完成设置。
顺腾摸瓜:IAgOrbitStateClassical(即,局部变量pClassical,也是Assig()方法的输入变量))
IAgOrbitStateClassical : IAgOrbitState { // IAgOrbitState相关属性和方法参见上一条摸瓜,本条忽略与父类的重复内容 // 属性 // // 坐标系类型,例如J2000、地固系、地惯系等,共定义了22种 enum AgECoordinateSystem CoordinateSystemType; // 坐标系(参数) IAgOrbitStateCoordinateSystemPtr CoordinateSystem; // 外形尺寸(size shape)类型,包括:高度、周期、半径、半长轴、平均运动等。 enum AgEClassicalSizeShape SizeShapeType; // 外形尺寸(参数) IAgClassicalSizeShapePtr SizeShape; // 方位/定位,包括:轨道倾角(Inclination)、近地点幅角(ArgOfPerigee)、 // 升交点类型(AscNodeType)及升交点(AscNode),说明升交点赤经不止一种类型 // 不能直接设置RAAN IAgClassicalOrientationPtr Orientation; // 位置类型,包括:升交角距(ArgumentOfLatitude)、偏近点角(EccentricAnomaly)、 // 平近点角(MeanAnomaly)、过升交点时间(TimePastAN)、 // 过近地点时间(TimePastPerigee)、真近点角(TrueAnomaly) enum AgEClassicalLocation LocationType; // 位置(参数) IAgClassicalLocationPtr Location; SAFEARRAY * SupportedCoordinateSystemTypes; // 接口方法 enum AgECoordinateSystem GetCoordinateSystemType ( ); void PutCoordinateSystemType (enum AgECoordinateSystem pVal ); IAgOrbitStateCoordinateSystemPtr GetCoordinateSystem ( ); enum AgEClassicalSizeShape GetSizeShapeType ( ); void PutSizeShapeType (enum AgEClassicalSizeShape pVal ); IAgClassicalSizeShapePtr GetSizeShape ( ); IAgClassicalOrientationPtr GetOrientation ( ); enum AgEClassicalLocation GetLocationType ( ); void PutLocationType (enum AgEClassicalLocation pVal ); IAgClassicalLocationPtr GetLocation ( ); SAFEARRAY * GetSupportedCoordinateSystemTypes ( ); }; |
最后定位到接口类IAgOrbitStateClassical的属性Orientation,继续摸瓜。
IAgClassicalOrientation : IUnknown { // 属性 double Inclination; // 轨道倾角 double ArgOfPerigee; // 近地点幅角 enum AgEOrientationAscNode AscNodeType; IAgOrientationAscNodePtr AscNode; // 接口方法 double GetInclination ( ); void PutInclination (double pVal ); double GetArgOfPerigee ( ); void PutArgOfPerigee (double pVal ); enum AgEOrientationAscNode GetAscNodeType ( ); void PutAscNodeType (enum AgEOrientationAscNode pVal ); IAgOrientationAscNodePtr GetAscNode ( ); }; |
只发现:轨道倾角(Inclination)、近地点幅角(ArgOfPerigee),升交点类型(AscNodeType)和升交点(AscNode),没有直接设置RAAN的地方,还得继续找!关键是,还没有设置AscNode的接口,只有GetAscNode,没有SetAscNode。好在是VC++编程直接都用的是IUnknown接口,应该是可以直接赋值。
AscNodeType和AscNode
enum AgEOrientationAscNode {// 升交点有两种表示方法,一种是LAN,另一种是RAAN eAscNodeUnknown = -1, eAscNodeLAN = 0, eAscNodeRAAN = 1 }; IAgOrientationAscNode : IUnknown {}; // 啥也没定义,只是为了下面的两个家伙有同一个父类而已 IAgOrientationAscNodeLAN : IAgOrientationAscNode { // 属性 double Value; // 方法 double GetValue ( ); void PutValue (double pVal ); }; IAgOrientationAscNodeRAAN : IAgOrientationAscNode { // 属性 double Value; // 方法 double GetValue ( ); void PutValue (double pVal ); }; |
终于定位!定制代码如下(下面仅展示了创建卫星函数里增加的局部代码,其他内容参见STK示例项目或本回前面示例代码):
// … // 轨道倾角 pClassical->Orientation->Inclination = rand() % 180; // 在插入第二颗卫星(编号1)时,指定其升交点赤经为例如30° if (iNext == 2) { pClassical->Orientation->AscNodeType = eAscNodeRAAN; IAgOrientationAscNodeRAANPtr ascNode; ascNode = pClassical->Orientation->AscNode; ascNode->Value = 30.0; } // Assign the orbit state // … |
运行效果如下(注:实例项目的界面经调整,并汉化),可以看到编号为1的卫星(紫色标记)的RAAN确实与众不同(默认添加的卫星初始时均在空间一条直线连线上,参见前面的代码注释)。
注:以上所有的信息均源于STK安装后默认自带的VC++编码的支持库,参见安装目录下‘CppInclude’文件夹,主要参考文件为*.tlh, *.tli。
关于以其他方式创建卫星,可通过本回的方法进行探索,STK应该是开放了所有的接口(未经本人证实),那个agstkobjects.tlh文件,有约8万行!
STK与VC++联合编程实战(第三回:加入卫星对象)相关推荐
- STK与VC++联合编程实战(第四回:由TLE数据插入卫星对象)
关于如何在STK中根据TLE数据插入卫星对象,参见本人另一篇文章: STK9中根据TLE数据插入卫星对象. 本回文探索如何利用STK提供的实例代码和接口直接通过VC++编程,由TLE数据插入卫星对象. ...
- 基于Winsock API的VC网络编程实战
基于Winsock API的VC网络编程实战 随着计算机信息技术的飞速发展,互联网与人类社会的工作.生活越来越紧密相关,它已经成为人类获取.交流信息的重要途径和手段.所以当前对于开发人员来说,网络编程 ...
- STK + C# + Cesium联合编程(一):技术路线验证
概述 本文演示了一个基于STK +C# + Cesium联合编程的应用实例.关于STK和Cesium编程网上在线资料丰富,本文主要解决了如果配置IIS服务以使得远程客户端能访问.初始化.以及执行服务器 ...
- Android编程实战——仿微信群聊-2——对象的网络传输
Android编程实战--仿微信群聊-2--对象的网络传输 项目源代码移步github 上一章服务器端有个消息类MyMessage类没有细讲,这里就说一下MyMessage和更重要的网络中对象的传输( ...
- VC黑客编程实战视频-破解网吧电影下载。
视频下载地址: 360云盘: 第一季:http://yunpan.cn/QG49aHbUDhXwi 第二季:http://yunpan.cn/QG4UgnI3uJ6vU 第三季:http://yunp ...
- JAVA并发编程实战---第三章:对象的共享(2)
线程封闭 如果仅仅在单线程内访问数据,就不需要同步,这种技术被称为线程封闭,它是实现线程安全性的最简单的方式之一.当某个对象封闭在一个线程中时,这种方法将自动实现线程安全性,即使被封闭的对象本生不是线 ...
- STK与C#联合编程
源码位置:<INSTALL DIR>\Help\stkX\Samples\CSharp\PlaceFinder\PlaceFinder.sln 此例在visual studio .NET ...
- JAVA并发编程实战---第三章:对象的共享
在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程序中,要对内存操作的执行顺序进行判断几乎无法得到正确的结果. 非原子的64位操作 当 ...
- java并发编程实战-第三章-对象的共享
3.1可见性 首先我们需要知道的是,java的线程都有自己独立的缓存,线程之间进行共享变量的交互是通过自身和缓存和主存的交互实现的. 如果线程的每次更改缓存都刷入主存,主存每次被一个线程的缓存修改,都 ...
最新文章
- 容器管理大战:Kubernetes vs.Docker Swarm与Amazon ECS
- Linux下用netstat查看网络状态、端口状态
- EL之Bagging(DTR):利用DIY数据集(预留30%数据+两种树深)训练Bagging算法(DTR)
- c语言用户输入编程,C语言入门教程-Printf:读取用户输入
- 接口自动化测试系列(一):HTTP状态码
- Swift中文教程(三)--流程控制
- 常见的几种负载均衡算法
- python中用于标识字符串的定界符_001.python-基础-Template的字符串格式化
- 5G精华问答 | 大数据和5G有什么关系?
- 南京宝坚电子,招聘图像算法工程师
- 在ASP.NET 中实现单用户登录(利用Cache, 将用户信息保存在服务器缓存中)[转]
- (CF#257)B. Jzzhu and Sequences
- 4月数据库流行度排行:深陷裁员风波的Oracle持续增长股价获新高
- ideaIU-2020.3.2安装教程以及导入第一个spring boot项目运行和环境配置教程
- Vue模板语法——插值
- 【bsauce读论文】 Playing for K(H)eaps: Understanding and Improving Linux Kernel Exploit Reliability
- PHP程序员必看书籍
- 【学术相关】交大博士学长:研究生计算机专业的方向选择!
- 详解目标检测的评价指标
- Mac 安装包破损 或 软件不受信任无法打开