Python3.6.8调用STK11.6仿真:从TLE文件读取某个ID号的卫星,外推星历并保存结果为*.xlsx文件
参考: Python与STK交互:创建场景,目标和计算目标参数并获取数据_奶灰不会飞-CSDN博客_python stk
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进行卫星星历外推完毕!")