STK and VC++ joint programming practice (the third round: adding satellite objects)

Special statement, I am a complete layman for astrophysics and orbital dynamics, not a subject direction, I only analyze from the code point of view and the code and data provided by STK as a reference, and welcome corrections from professionals. If you don't like it, don't spray it!

Continue to take the VC++ code example Events project provided by STK as an example.

The code for adding satellites is as follows (in the Helper source file, I added comments myself):

void CObjectModelHelper::CreateSatellite(STKObjects::IAgStkObjectRootPtr pRoot)

{

    static int                iNext = 0;

    char                      buf[255];

    double                     aporad,

                              horse

    _bstr_t                   bstrName;

    IAgOrbitStateClassicalPtr pClassical;

    IAgStkObjectPtr           pNewObj;     // STK Object

    IAgSatellitePtr            pSat;        // STK satellite object

    IAgVePropagatorTwoBodyPtr pTwoBodyProp; // TwoBody orbit predictor

    IAgClassicalSizeShapeRadiusPtr pRadius;

    // Build the satellite name

    drown(iNext++, buf, 10);

    bstrName = "Satellite";

    bstrName += buf;

    // Make sure the NewScenario operation is executed first

    ASSERT(pRoot != NULL);

    // Add a new instance of the Satellite to the scenario

    // eSatellite is defined in the file agstkobjects.tlh, representing the satellite object in STK

    //enum AgESTKObjectType

    //{

    //  ... = 17,

    //  eSatellite = 18,

    //  ... = 19,

    //};

    // Note: Most of the STK objects in this example are declared in the agstkobjects.tlh/.tli file (prototype)

    // IAgStkObjectRootPtr pRoot , this is the ROOT (root) of all objects in the STK application

    // 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();

}

流程大致分析:

  1. 在当前场景中首先增加一个卫星对象(注:此时只是增加了一个卫星对象,在没有指定卫星的轨道预报器(Orbit Propagator)并根据轨道预报器类型初始化轨道参数之前,三维场景并不会绘制卫星状态,也绘制不出来,这与其他类型的对象不同,也可以通过STK程序操作验证)。
  2. 获取当前场景,获取当前场景的对象为pRoot(个人理解其代表了一个独立运行的STK应用程序/进程)。
  3. 由场景对象获取当前场景的对象集合(IAgStkObjectCollection),这个集合应该是包含了场景中的所有对象,不出例外的话是一个树型结构。
  4. 由(场景)对象集合创建一个新的对象,即本例中new一个卫星对象。
  5. 将新建的对象(StkObject)赋值给卫星对象(Satellite),以便进行后续针对卫星类型对象的初始化操作。
  6. 指定卫星的轨道预报器类型,本例中为二体轨道预报器(Two Body),后面接着需要指定的轨道预报器进行不同的初始状态设置。
  7. 将当前预报器的初始状态表示转换为经典轨道状态表示,这是针对二体轨道预报器的操作,不知道其他类型的轨道预报器该如何操作,下一步继续探索!
  8. 对经典轨道状态初始化,包括近地点、远地点、轨道倾角,其他的轨道参数保持了默认值。
  9. 将设置后的轨道数据赋值给当前卫星对象的轨道预报器(…->Assign(pClassical))。
  10. 由轨道预报器执行轨道计算。(计算完毕后,场景会自动更新)

下面通过指定二体轨道预报器的其他轨道参数,以升交点赤经(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接口)包括:

  1. 轨道计算(Propagate());
  2. 设置开始时间(PutStartTime());
  3. 结束时间(PutStopTime());
  4. 计算步长(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万行!

Guess you like

Origin blog.csdn.net/wangyulj/article/details/123904932