Skip to content

Commit a459680

Browse files
committed
Add Repeat Ground Trace Script
1 parent ca21a35 commit a459680

File tree

2 files changed

+387
-0
lines changed

2 files changed

+387
-0
lines changed
Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "0462fffd-906b-415b-9ffe-3b9e926aab00",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"#READ ME\n",
11+
"##################################################################################################################################################\n",
12+
"#Determine the number of passes until the satellite repeats its ground trace\n",
13+
"#Definiton of pass break should be definied in the satellite's properties; whether it is ascending or descedning at the equator\n",
14+
"#This script loads the Passes data provider. This data provider gives the pass number, latitude at pass break and longitude at pass break, \n",
15+
"#as well as the start and stop times of each pass interval. The latitude at the pass break is ~zero, since the pass break is defined at the equator. \n",
16+
"#Whether the pass break is defined as ascending or descending only depends on the users prefered convention, as the data provider provides passes only at\n",
17+
"#the node where the break is defined. This means that the latitude and longitude rates do not have to be checked for matching direction of pass. \n",
18+
"#The logic implemented checks for a repeating logitude at pass break value. \n",
19+
"\n",
20+
"\n",
21+
"#User inputs:\n",
22+
"\n",
23+
"#The user has to input the name of the satellite, as well as the reference pass number to begin the search from. A reference data frame is displayed \n",
24+
"#so that the user can pick a pass number without having to generate a custom report inside of STK. "
25+
]
26+
},
27+
{
28+
"cell_type": "code",
29+
"execution_count": 1,
30+
"id": "961f06e2-636d-4219-af40-53596400c470",
31+
"metadata": {},
32+
"outputs": [],
33+
"source": [
34+
"import datetime as dt\n",
35+
"import numpy as np\n",
36+
"import os\n",
37+
"import pandas as pd\n",
38+
"\n",
39+
"# Get reference to running STK instance\n",
40+
"from agi.stk12.stkdesktop import STKDesktop\n",
41+
"\n",
42+
"stk = STKDesktop.AttachToApplication()\n",
43+
"\n",
44+
"# Get the IAgStkObjectRoot interface\n",
45+
"root = stk.Root"
46+
]
47+
},
48+
{
49+
"cell_type": "code",
50+
"execution_count": 2,
51+
"id": "b516da25-6a28-4c61-b954-01996d2b101f",
52+
"metadata": {},
53+
"outputs": [
54+
{
55+
"data": {
56+
"text/html": [
57+
"<div>\n",
58+
"<style scoped>\n",
59+
" .dataframe tbody tr th:only-of-type {\n",
60+
" vertical-align: middle;\n",
61+
" }\n",
62+
"\n",
63+
" .dataframe tbody tr th {\n",
64+
" vertical-align: top;\n",
65+
" }\n",
66+
"\n",
67+
" .dataframe thead th {\n",
68+
" text-align: right;\n",
69+
" }\n",
70+
"</style>\n",
71+
"<table border=\"1\" class=\"dataframe\">\n",
72+
" <thead>\n",
73+
" <tr style=\"text-align: right;\">\n",
74+
" <th></th>\n",
75+
" <th>pass number</th>\n",
76+
" <th>start time</th>\n",
77+
" <th>end time</th>\n",
78+
" <th>lat of pass break</th>\n",
79+
" <th>lon of pass break</th>\n",
80+
" </tr>\n",
81+
" </thead>\n",
82+
" <tbody>\n",
83+
" <tr>\n",
84+
" <th>1</th>\n",
85+
" <td>28163</td>\n",
86+
" <td>12 Aug 2024 17:26:14.494977581</td>\n",
87+
" <td>12 Aug 2024 19:02:46.514954408</td>\n",
88+
" <td>-0.0873947735225083</td>\n",
89+
" <td>8.601422286373392</td>\n",
90+
" </tr>\n",
91+
" <tr>\n",
92+
" <th>2</th>\n",
93+
" <td>28164</td>\n",
94+
" <td>12 Aug 2024 19:02:46.514954408</td>\n",
95+
" <td>12 Aug 2024 20:39:18.533603963</td>\n",
96+
" <td>-0.08727234622554693</td>\n",
97+
" <td>-15.532017288934808</td>\n",
98+
" </tr>\n",
99+
" <tr>\n",
100+
" <th>3</th>\n",
101+
" <td>28165</td>\n",
102+
" <td>12 Aug 2024 20:39:18.533603963</td>\n",
103+
" <td>12 Aug 2024 22:15:50.550926253</td>\n",
104+
" <td>-0.08714981951087282</td>\n",
105+
" <td>-39.66545134781159</td>\n",
106+
" </tr>\n",
107+
" <tr>\n",
108+
" <th>4</th>\n",
109+
" <td>28166</td>\n",
110+
" <td>12 Aug 2024 22:15:50.550926253</td>\n",
111+
" <td>12 Aug 2024 23:52:22.566921262</td>\n",
112+
" <td>-0.08702719257195864</td>\n",
113+
" <td>-63.798879881983495</td>\n",
114+
" </tr>\n",
115+
" <tr>\n",
116+
" <th>5</th>\n",
117+
" <td>28167</td>\n",
118+
" <td>12 Aug 2024 23:52:22.566921262</td>\n",
119+
" <td>13 Aug 2024 01:28:54.581588974</td>\n",
120+
" <td>-0.08690446607985204</td>\n",
121+
" <td>-87.93230281204092</td>\n",
122+
" </tr>\n",
123+
" <tr>\n",
124+
" <th>...</th>\n",
125+
" <td>...</td>\n",
126+
" <td>...</td>\n",
127+
" <td>...</td>\n",
128+
" <td>...</td>\n",
129+
" <td>...</td>\n",
130+
" </tr>\n",
131+
" <tr>\n",
132+
" <th>354</th>\n",
133+
" <td>28516</td>\n",
134+
" <td>5 Sep 2024 09:21:15.076499704</td>\n",
135+
" <td>5 Sep 2024 10:57:46.627912830</td>\n",
136+
" <td>-0.03837724529765448</td>\n",
137+
" <td>129.84227401603937</td>\n",
138+
" </tr>\n",
139+
" <tr>\n",
140+
" <th>355</th>\n",
141+
" <td>28517</td>\n",
142+
" <td>5 Sep 2024 10:57:46.627912830</td>\n",
143+
" <td>5 Sep 2024 12:34:18.177999064</td>\n",
144+
" <td>-0.0382242965810016</td>\n",
145+
" <td>105.71079509437088</td>\n",
146+
" </tr>\n",
147+
" <tr>\n",
148+
" <th>356</th>\n",
149+
" <td>28518</td>\n",
150+
" <td>5 Sep 2024 12:34:18.177999064</td>\n",
151+
" <td>5 Sep 2024 14:10:49.726758400</td>\n",
152+
" <td>-0.03807127575269202</td>\n",
153+
" <td>81.57932169859559</td>\n",
154+
" </tr>\n",
155+
" <tr>\n",
156+
" <th>357</th>\n",
157+
" <td>28519</td>\n",
158+
" <td>5 Sep 2024 14:10:49.726758400</td>\n",
159+
" <td>5 Sep 2024 15:47:21.274190835</td>\n",
160+
" <td>-0.037918183457602166</td>\n",
161+
" <td>57.44785387055359</td>\n",
162+
" </tr>\n",
163+
" <tr>\n",
164+
" <th>358</th>\n",
165+
" <td>28520</td>\n",
166+
" <td>5 Sep 2024 15:47:21.274190835</td>\n",
167+
" <td>5 Sep 2024 16:00:00.000000000</td>\n",
168+
" <td>-0.037765020105909215</td>\n",
169+
" <td>33.31639160611295</td>\n",
170+
" </tr>\n",
171+
" </tbody>\n",
172+
"</table>\n",
173+
"<p>358 rows × 5 columns</p>\n",
174+
"</div>"
175+
],
176+
"text/plain": [
177+
" pass number start time \\\n",
178+
"1 28163 12 Aug 2024 17:26:14.494977581 \n",
179+
"2 28164 12 Aug 2024 19:02:46.514954408 \n",
180+
"3 28165 12 Aug 2024 20:39:18.533603963 \n",
181+
"4 28166 12 Aug 2024 22:15:50.550926253 \n",
182+
"5 28167 12 Aug 2024 23:52:22.566921262 \n",
183+
".. ... ... \n",
184+
"354 28516 5 Sep 2024 09:21:15.076499704 \n",
185+
"355 28517 5 Sep 2024 10:57:46.627912830 \n",
186+
"356 28518 5 Sep 2024 12:34:18.177999064 \n",
187+
"357 28519 5 Sep 2024 14:10:49.726758400 \n",
188+
"358 28520 5 Sep 2024 15:47:21.274190835 \n",
189+
"\n",
190+
" end time lat of pass break \\\n",
191+
"1 12 Aug 2024 19:02:46.514954408 -0.0873947735225083 \n",
192+
"2 12 Aug 2024 20:39:18.533603963 -0.08727234622554693 \n",
193+
"3 12 Aug 2024 22:15:50.550926253 -0.08714981951087282 \n",
194+
"4 12 Aug 2024 23:52:22.566921262 -0.08702719257195864 \n",
195+
"5 13 Aug 2024 01:28:54.581588974 -0.08690446607985204 \n",
196+
".. ... ... \n",
197+
"354 5 Sep 2024 10:57:46.627912830 -0.03837724529765448 \n",
198+
"355 5 Sep 2024 12:34:18.177999064 -0.0382242965810016 \n",
199+
"356 5 Sep 2024 14:10:49.726758400 -0.03807127575269202 \n",
200+
"357 5 Sep 2024 15:47:21.274190835 -0.037918183457602166 \n",
201+
"358 5 Sep 2024 16:00:00.000000000 -0.037765020105909215 \n",
202+
"\n",
203+
" lon of pass break \n",
204+
"1 8.601422286373392 \n",
205+
"2 -15.532017288934808 \n",
206+
"3 -39.66545134781159 \n",
207+
"4 -63.798879881983495 \n",
208+
"5 -87.93230281204092 \n",
209+
".. ... \n",
210+
"354 129.84227401603937 \n",
211+
"355 105.71079509437088 \n",
212+
"356 81.57932169859559 \n",
213+
"357 57.44785387055359 \n",
214+
"358 33.31639160611295 \n",
215+
"\n",
216+
"[358 rows x 5 columns]"
217+
]
218+
},
219+
"execution_count": 2,
220+
"metadata": {},
221+
"output_type": "execute_result"
222+
}
223+
],
224+
"source": [
225+
"#Get a reference to the scenario object\n",
226+
"scenario = root.CurrentScenario\n",
227+
"\n",
228+
"##################################################################################################################################\n",
229+
"#Get Satellite Object in scenario#\n",
230+
"#Change the name of the satellite in '' #\n",
231+
"\n",
232+
"Satellite=scenario.Children.GetItemByName('RCM-1_44322')\n",
233+
"\n",
234+
"#Get the Passes data provider\n",
235+
"passD=Satellite.DataProviders.Item(\"Passes\")\n",
236+
"passDgroup=passD.ExecElements(scenario.StartTime, scenario.StopTime,['Pass Number', 'Start Time', 'End Time','Lat of Pass Break','Lon of Pass Break'])\n",
237+
"#turn into a pandas data frame\n",
238+
"passDataSet = passDgroup.DataSets.ToPandasDataFrame()\n",
239+
"passDataSet.drop([0],inplace = True)\n",
240+
"#display data frame for reference\n",
241+
"passDataSet"
242+
]
243+
},
244+
{
245+
"cell_type": "code",
246+
"execution_count": 3,
247+
"id": "7a2933b0-e019-43c8-b982-0d048e85fa9d",
248+
"metadata": {},
249+
"outputs": [],
250+
"source": [
251+
"\n",
252+
"\n",
253+
"#####################################################################################################################################################\n",
254+
"#Reference input you imput to start to search\n",
255+
"Input_PassNumber='28163'\n",
256+
"#tolerance for the longitude at pass break match\n",
257+
"sigma=0.8\n",
258+
"\n",
259+
"#The row of the dataset correcsponding to the user input time\n",
260+
"reference_row = passDataSet.loc[passDataSet['pass number'] == Input_PassNumber]\n",
261+
"passNumber_ref = float(reference_row['pass number'])\n",
262+
"\n",
263+
"#The index of the row corresponding to the matched row\n",
264+
"index_input = reference_row.index\n",
265+
"\n",
266+
"\n",
267+
"#function to get the time of repeat ground trace\n",
268+
"def get_repeated_pass_number():\n",
269+
" #locate where the time is the reference time\n",
270+
" reference_row = passDataSet.loc[passDataSet['pass number'] == Input_PassNumber]\n",
271+
" \n",
272+
" #turn the value into a number\n",
273+
" #pass number and lon at pass break corresponding to the reference row\n",
274+
" lon_ref = float(reference_row['lon of pass break'])\n",
275+
" passNumber_ref = float(reference_row['pass number'])\n",
276+
"\n",
277+
" #threshold bounds for lon search\n",
278+
" upperThreshLon = lon_ref + sigma\n",
279+
" lowerThreshLon = lon_ref - sigma\n",
280+
"\n",
281+
" #loop through the data frame rows\n",
282+
" for index, passD in passDataSet.iterrows():\n",
283+
"\n",
284+
" #only loop through the rows after the input time, ignore everything before\n",
285+
" if index > index_input[0] :\n",
286+
" #Declare data for current step\n",
287+
" Time=passD.at['start time']\n",
288+
" Lon=float(passD.at['lon of pass break'])\n",
289+
" Pass=passD.at['pass number']\n",
290+
" \n",
291+
" repeatLon=lon_ref\n",
292+
" \n",
293+
" #apply logic\n",
294+
" if Lon <= upperThreshLon and Lon >= lowerThreshLon :\n",
295+
" TimeOfRepeat = Time\n",
296+
" RepeatPassNumber = Pass\n",
297+
" return RepeatPassNumber, TimeOfRepeat"
298+
]
299+
},
300+
{
301+
"cell_type": "code",
302+
"execution_count": 4,
303+
"id": "7f2eec78-1e97-47fb-a2a1-b13a258a0055",
304+
"metadata": {},
305+
"outputs": [
306+
{
307+
"name": "stdout",
308+
"output_type": "stream",
309+
"text": [
310+
"28342.0\n",
311+
"24 Aug 2024 17:25:24.923887527\n"
312+
]
313+
}
314+
],
315+
"source": [
316+
"#run function and assign the pass number and time of the repeat \n",
317+
"repeat_pass, repeat_time = get_repeated_pass_number()\n",
318+
"repeat_pass=float(repeat_pass)\n",
319+
"#print for reference\n",
320+
"print(repeat_pass)\n",
321+
"print(repeat_time)"
322+
]
323+
},
324+
{
325+
"cell_type": "code",
326+
"execution_count": 5,
327+
"id": "04e7ac00-3ca9-4a39-bed5-9894100bdf67",
328+
"metadata": {},
329+
"outputs": [
330+
{
331+
"data": {
332+
"text/plain": [
333+
"179.0"
334+
]
335+
},
336+
"execution_count": 5,
337+
"metadata": {},
338+
"output_type": "execute_result"
339+
}
340+
],
341+
"source": [
342+
"#subtracting the pass number at the reference time from the pass number at the repeat time to get the number of passes with\n",
343+
"#repect to the reference time\n",
344+
"Number_of_passes = repeat_pass - passNumber_ref\n",
345+
"Number_of_passes"
346+
]
347+
}
348+
],
349+
"metadata": {
350+
"kernelspec": {
351+
"display_name": "Python 3 (ipykernel)",
352+
"language": "python",
353+
"name": "python3"
354+
},
355+
"language_info": {
356+
"codemirror_mode": {
357+
"name": "ipython",
358+
"version": 3
359+
},
360+
"file_extension": ".py",
361+
"mimetype": "text/x-python",
362+
"name": "python",
363+
"nbconvert_exporter": "python",
364+
"pygments_lexer": "ipython3",
365+
"version": "3.8.10"
366+
}
367+
},
368+
"nbformat": 4,
369+
"nbformat_minor": 5
370+
}

StkAutomation/Python/Problem_Specific/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,23 @@ This script will take the prinicple axes of a covariance matrix and turn it into
170170

171171
---
172172

173+
## [NumberOfPassesUntilRepeatGroundTrace.ipynb](NumberOfPassesUntilRepeatGroundTrace.ipynb)
174+
175+
Determine the number of passes until the satellite repeats its ground trace. Definiton of pass break should be definied in the satellite's properties; whether it is ascending or descedning at the equator. This script loads the Passes data provider. This data provider gives the pass number, latitude at pass break and longitude at pass break, as well as the start and stop times of each pass interval. The latitude at the pass break is ~zero, since the pass break is defined at the equator. Whether the pass break is defined as ascending or descending only depends on the users prefered convention, as the data provider provides passes only at the node where the break is defined. This means that the latitude and longitude rates do not have to be checked for matching direction of pass. The logic implemented checks for a repeating logitude at pass break value.
176+
177+
User inputs:
178+
179+
The user has to input the name of the satellite, as well as the reference pass number to begin the search from. A reference data frame is displayed so that the user can pick a pass number without having to generate a custom report inside of STK.
180+
181+
### Dependencies
182+
183+
* Licenses: [STK Pro](https://www.ansys.com/content/dam/amp/2022/june/webpage-requests/stk-product-page/brochures/stk-pro-brochure.pdf)
184+
* Other Scripts: N/A
185+
* Scenario: N/A
186+
* Third-Party Libraries: numpy, pandas
187+
188+
---
189+
173190
## [EOIRTextureMaps](EOIRTextureMaps)
174191

175192
This folder contains examples of converting NASA Earthdata HDF4 and HDF5 files into a format that can be imported into STK as a texture map. This contains examples of navigating the HDF standard format to locate corner point metadata required by STK and as well as detailing the conversion of data to usable information. This information is then written to a csv file that can be natively read by STK's EOIR capability. Check out [this FAQ](https://analyticalgraphics.force.com/faqs/articles/Knowledge/Loading-EOIR-Texture-Maps-From-NASA-s-Earthdata) for more detailed workflow information.

0 commit comments

Comments
 (0)