当前位置: 首页 > 工具软件 > STK/Unit > 使用案例 >

Python3.6.8调用STK11.6仿真:从TLE文件读取某个ID号的卫星,外推星历并保存结果为*.xlsx文件

麻桐
2023-12-01

Python3.6.8调用STK11.6仿真:从TLE文件读取某个ID号的卫星,外推星历并保存结果为*.xlsx文件

说明: 根据CSDN的'奶灰不会飞'博主的帖子,稍微改写实现

参考: Python与STK交互:创建场景,目标和计算目标参数并获取数据_奶灰不会飞-CSDN博客_python stk

代码、TLE文件、生成结果打包上传:

Python+STK联合仿真:外推星历_从TLE文件读取某个ID号的卫星.zip-互联网文档类资源-CSDN下载

直接上代码:

# -*- coding:utf-8 -*-
# JSLS备注
"""
① 根据如下技术帖子改写:
# 《CSDN__奶灰不会飞:Python与STK交互:创建场景,目标和计算目标参数并获取数据.mhtml》
#  https://blog.csdn.net/weixin_43534654/article/details/107020445

② 代码开展的工作总结:
   1、 COM对象编程,调试时可看见 COM组件对象 详情;
   2、 将 STK 的时间格式 '1 Jan 2022 08:00:00' 转换成了可读性强的 '2022-01-01 08:00:00' 格式;
   3、 使用了 pandas 库 第三方包,时刻、半长轴、纬度、经度等数据,进行批量处理;
   4、 结果文件存储为 *.xlsx Excel文件。
"""

# %%import
import datetime
import os
import time

import pandas as pd

# JSLS添加
"""
Python调用STK11.6
可以在STK软件的【STK Help】网页帮助里看到详细介绍:
file:///C:/Program%20Files/AGI/STK%2011/Help/index.htm#training/StartPython.htm%3FTocPath%3DTraining%7CLevel%25202%2520-%2520Advanced%2520Training%7C_____10
网页帮助的文档标题《Part 16: Integrating STK with Python》
"""
# Set up your python workspace
from win32api import GetSystemMetrics
"""
报错:ImportError: No module named win32api
需要安装 pypiwin32 , 手动安装 pypiwin32 如下: 
pip install pywin32-226-cp36-cp36m-win32.whl
"""

import comtypes
from comtypes.client import CreateObject

# 以下2句:是因为【 root=uiApplication.Personality2 】 运行后,生成了【comtypes.gen】
from comtypes.gen import STKUtil
from comtypes.gen import STKObjects


# TLE文件中指定 ID号的卫星,进行轨道外推
def createSatellite(path_tle, satelliteID, starttime, stoptime, steptime=300):
    """  TLE文件中指定 ID号的卫星,进行轨道外推
    输入:  path_tle:     TLE文件 全路径
            satelliteID: TLE文件中 某颗卫星的 ID
            starttime:   外推轨道的起始时刻
            stoptime:    外推轨道的结束时刻
            steptime:    外推轨道的步长时间(单位:秒)
    输出:  'result01.xlsx' 和 'result01.xlsx' 轨道外推结果文件
    注意:  steptime时间步长: 默认为300秒,即5分钟
    """
    # 首先创建卫星
    """ COM对象编程,需要从 satellite 开始就用[QueryInterface]进行类型转换,而后使用 satellite2.Propagator 
    file:///C:/Program%20Files/AGI/STK%2011/Help/Programming/index.htm#stkObjects/ObjectModelTutorial.html?Highlight=queryinterface
    """
    
    satellite = root.CurrentScenario.Children.New(STKObjects.eSatellite, '44257__Starlink-43')  # eSatellite
    # 从 satellite 开始就用[QueryInterface]进行类型转换
    satellite_QI = satellite.QueryInterface(STKObjects.IAgSatellite)
    # 设置轨道外推模型: [EPropagator]参数为4 代表 ePropagatorSGP4
    satellite_QI.SetPropagatorType(STKObjects.ePropagatorSGP4)  #
    """ [EPropagator]的取值 ePropagatorSGP4 ,实际上是 4 
    file:///C:/Program%20Files/AGI/STK%2011/Help/Programming/index.htm#DocX/STKObjects~IAgSatellite~SetPropagatorType.html?Highlight=SetPropagatorType
    """

    # 卫星 的 轨道外推器
    propagator = satellite_QI.Propagator
    propagator_QI = propagator.QueryInterface(STKObjects.IAgVePropagatorSGP4)
    # 用tle根数生成卫星,注意:
    # 1、该函数有两个输入参数皆为字符串,'NORADID','根数文件路径'
    # 2、根数文件里同一目标不能有相同历元根数
    # propagator_QI.CommonTasks.AddSegsFromFile('ID','path.txt'),txt中要有该卫星的根数
    #   JSLS备:[AddSegsFromFile] 方法只能从 TLE根数文件中 添加 1颗卫星!
    #       ★★★逻辑很简单 ==> [AddSegsFromFile] 来自 satellite_QI.Propagator
    #                            ==>  来自 root.CurrentScenario.Children.New 创建的单颗卫星!
    #                                  ==> 1颗卫星 怎么可以添加 多颗卫星的 TLE根数呢!
    #            后续的[AddSegsFromFile]调用仍然成功,但采取”覆盖方式“添加,只保留最后一次添加的卫星
    #            需注意 [AddSegsFromFile] 方法 没有返回值 来表征是否运行成功。
    #propagator_QI.CommonTasks.AddSegsFromFile('44257', path_tle)
    # 上面 的 '44257'ID号 的 卫星, 改用 形参[satelliteID] 指定
    print("准备外推轨道的卫星ID为:", satelliteID)
    propagator_QI.CommonTasks.AddSegsFromFile(satelliteID, path_tle)
    #propagator_QI.CommonTasks.AddSegsFromFile('44238', path_tle)
    #propagator_QI.CommonTasks.AddSegsFromFile('49750', path_tle)
    #propagator_QI.CommonTasks.AddSegsFromFile('46070', path_tle)
    """ AddSegsFromFile 自带网页帮助:
    在指定的 TLE 文件中搜索与指定 SSC 编号匹配的 TLE,并将它们添加到集合中。
    Searches the specified TLE file for TLEs matching the specified SSC number and adds them to the collection.
    """
    commonTasks = propagator_QI.CommonTasks
    print(commonTasks)  # <POINTER(IAgVePropagatorSGP4CommonTasks) ptr=0x8f12dcc at 9d238a0>
    ########################################################################################
    # JSLS备注: ①外推器[IAgVePropagator]不能添加多颗卫星,即,一次只能对 1颗卫星进行轨道外推!
    #             ②STK自带的网页帮助里,[IAgVePropagatorSGP4]接口包含[Segments]属性
    #             ③[IAgVePropagatorSGP4]的[Segments]属性的类型为[IAgVeSGP4SegmentCollection]接口
    """ STK网页帮助中搜索 "IAgVePropagatorSGP4 Interface"
    ① CommonTasks.AddSegsFromFile('44257', path_tle) 用来添加 TLE文件 中的 指定ID号的卫星
    ② 添加卫星的 ID号 保存在 Segments.SSCNumber 里面
    ③ 卫星的 详细参数 保存在 segments.Item[0] (有且仅有 1个 卫星元素,即只有 Item[0])
    """
    segments = propagator_QI.Segments
    print("从TLE文件读取的当前卫星的ID为:", segments.SSCNumber)
    segmentItem = segments.Item[0]
    print(segmentItem)  # IAgVeSGP4Segment ==> 用于 SGP4 propagator 外推器的接口
    """ 调试时 的 segments.Item[0] 详情 :
    对应的 TLE 文件中的 TLE根数: ID值为  44257 
STARLINK-43             
1 44257U 19029Y   22001.26759038  .00281389  00000+0  16789-2 0  9991
2 44257  52.9902   4.6867 0007876  73.1914 286.9968 15.76532477145763
    ArgOfPerigee = 73.1914
    BStar = 0.0016789
    Classification = 'U'
    Eccentricity = 0.0007876
    Enabled = True
    Epoch = 22001.26759038
    Inclination = 52.9902
    IntlDesignator = '19029Y  '
    MeanAnomaly = 286.9968
    MeanMotion = 0.06568885320833333
    MeanMotionDot = 0.00281389
    MotionDotDot = 0.0
    RAAN = 4.6867
    Range = 0.0
    RevNumber = 14576
    SSCNum = '44257'
    SwitchTime = '1 Jan 2022 06:25:19.809'
    SwitchingMethod = 0
    """

    propagator_QI.AutoUpdateEnabled = True
    # 进行 轨道外推
    propagator_QI.Propagate()


    # 通过Dataprovider接口计算卫星参数
    # 推荐使用这些方式连接接口
    # There are 4 Methods to get DP From a Path depending on the kind of DP:
    #   GetDataPrvTimeVarFromPath
    #   GetDataPrvIntervalFromPath
    #   GetDataPrvInfoFromPath
    #   GetDataPrvFixeDataromPath
    # Orbit元素:半长轴等
    satOrbitDP = satellite.DataProviders.GetDataPrvTimeVarFromPath('Classical Elements/J2000')
    results_orbit = satOrbitDP.Exec(starttime, stoptime, steptime)  # 时间步长300秒,即5分钟
    # (t1,t2,时间步长)t1,t2都必须是符合STK格式的时间字符串:'1 Jan 2020 04:00:00'
    # LLA State 经纬度轨迹
    satLLADP = satellite.DataProviders.GetDataPrvTimeVarFromPath('LLA State/Fixed')
    results_LLA = satLLADP.Exec(starttime, stoptime, steptime)  # 时间步长300秒,即5分钟
    # 组:Classical Elements,类:J2000,计算元素:Time x y z等等
    # 使用Exec,会计算类下所有元素的值,更多详情请参考STK帮助文档
    # GET DATA
    # 从DataSets中获取数据有两种方式:1、序号;2、元素名称。
    # satax = results_orbit.DataSets.GetDataSetByName('Semi-major Axis').GetValues()
    # [0]:'Time' [1]:'Semi-major Axis'
    sat_time = results_orbit.DataSets[0].GetValues()  # 注意有多个DataSets,用索引进行访问
    sat_sma = results_orbit.DataSets[1].GetValues()
    sat_inc = results_orbit.DataSets[3].GetValues()
    sat_lat = results_LLA.DataSets[1].GetValues()
    sat_lon = results_LLA.DataSets[2].GetValues()
    # create new dataframes to store these data
    Data = pd.DataFrame(
        columns=('Time (UTC)',
                 'Semi-major Axis (km)', 'Inclination (deg)',
                 'latitude (deg)', 'longitude (deg)'))
    Data_a = pd.DataFrame(columns=('Time', 'Semi-major Axis (km)'))
    # 给Data,Data_a赋值
    for j in range(0, len(sat_time)):
        ################################################################
        # 将 STK 的时间格式 '1 Jan 2022 08:00:00' 转换成了可读性强的 '2022-01-01 08:00:00' 格式
        t = sat_time[j].split('.', 1)[0]    # 取【秒.毫秒】前面的时间,比如 '1 Jan 2022 08:00:00'
        # 转换输出时间为时间戳方便筛选核计算数据
        # STK输出的时间格式样式:1 Jan 2020 04:00:00
        t_stamp = time.strptime(t, '%d %b %Y %H:%M:%S')
        t_stamp = time.mktime(t_stamp) / 3600   # t_stamp 用于存储到 pd 数据,写入 Excel 文件
        # 转换输出时间为格式时间便于显示以及读取
        t = datetime.datetime.strptime(t, '%d %b %Y %H:%M:%S')
        t = datetime.datetime.strftime(t, '%Y-%m-%d %H:%M:%S')  # 至此,时间转换成的格式: '2022-01-01 08:00:00'
        ################################################################
        
        sma = sat_sma[j]
        inc = sat_inc[j]
        lat = sat_lat[j]
        lon = sat_lon[j]
        Data_a = Data_a.append(pd.DataFrame(
            {'Time': [t_stamp], 'Semi-major Axis (km)': [sma]}),
            ignore_index=True)
        # print(Data_a.head())
        Data = Data.append(pd.DataFrame(
            {'Time (UTC)': [t],
             'Semi-major Axis (km)': [sma], 'Inclination (deg)': [inc],
             'latitude (deg)': [lat], 'longitude (deg)': [lon]}),
            ignore_index=True)
        # print(Data.head())

    # 存储Data
    fileNameSaved01 = '[' + satelliteID + ']卫星星历外推结果(UTC时刻,半长轴,倾角,纬度,经度).xlsx'
    fileNameSaved02 = '[' + satelliteID + ']卫星星历外推结果(积秒时刻,半长轴).xlsx'
    Data.to_excel(target_excel_dir + '/' + fileNameSaved01,
                  'ID_' + satelliteID, float_format='%.3f', index=False)
    Data_a.to_excel(target_excel_dir + '/' + fileNameSaved02,
                   'ID_' + satelliteID, float_format='%.3f', index=False)





# 创建数据存储路径,注意:全路径必须为全英文,如果为中文会报错
target_excel_dir = r'E:\_WS_STK_use_Python\CSDN__weixin_43534654'
if not os.path.exists(target_excel_dir):
    os.makedirs(target_excel_dir)

# 打开STK11软件  type(uiApplication) 为 <class 'comtypes.POINTER(_IAgUiApplication)'>
uiApplication = CreateObject("STK11.Application")
# 显示 STK11 软件界面
uiApplication.Visible = True
uiApplication.UserControl = True

# Personality2 返回【STK对象模型的根对象】的新实例 IAgStkObjectRoot 接口
# 假如是 Personality, 则 打开现有STK对象
root = uiApplication.Personality2  # root类型: IAgStkObjectRoot

# 创建 一个新的场景
root.NewScenario("Starlink2022")

# STK 对象模型 单位偏好设置 SetCurrentUnit
# STK Object Model Unit Preferences
# file:///C:/Program%20Files/AGI/STK%2011/Help/Programming/index.htm#DocX/STKUtil~IAgUnitPrefsDimCollection~SetCurrentUnit.html?Highlight=UnitPreferences%20SetCurrentUnit
root.UnitPreferences.SetCurrentUnit('DateFormat', 'UTCG')  # 设置日期单位为 Gregorian UTC (UTCG)

# 创建的场景 赋给 scenario
#   type(scenario) 为 <class 'comtypes.POINTER(IAgStkObject)'>
scenario = root.CurrentScenario
#         Remarks: Cast the returned object to IAgScenario to access scenario methods and properties
#                    COM组件编程 对象转换 用 "QueryInterface"
# 设置 仿真分析 的时间段
scenario2 = scenario.QueryInterface(STKObjects.IAgScenario)
# 设置场景时间:有两种方法:①方法注释掉;使用第②种方法
# scenario2.SetTimePeriod('Today', '+24hr')  # ①方法 开始时间:今天;结束时间:24小时
# ②方法:设置场景时间
scenario2.StartTime = '1 Jan 2022 08:00:00.00'
scenario2.StopTime = '2 Jan 2022 18:00:00.00'

# %%定义函数创建卫星并导出数据
# path_tle:D:/xxx/xxx.txt存储目标的tle文件夹
#    加'r'是防止字符转义的,如果路径中出现'\t'不加r,\t就会被转义,而加了'r'之后'\t'就能保留原有的样子。
path_tle = r'E:\_WS_STK_use_Python\CSDN__weixin_43534654\starlink_20220102.txt'
currentSatelliteID = r'44257'
t1 = scenario2.StartTime
t2 = scenario2.StopTime
stepTime = 300  # 外推轨道的步长时间为 5分钟
# 你也可以自定义计算卫星参数的时间区间,但需要在场景时间范围内。
t3 = '1 Jan 2022 08:00:00.00'
t4 = '1 Jan 2022 09:00:00.00'
# 可以用root多次设置场景时间
createSatellite(path_tle, currentSatelliteID, t1, t2, stepTime)

print("Python连接STK11进行卫星星历外推完毕!")

 类似资料: