1 /*
2 Gpredict: Real-time satellite tracking and orbit prediction program
3
4 Copyright (C) 2001-2009 Alexandru Csete, OZ9AEC.
5
6 Authors: Alexandru Csete <oz9aec@gmail.com>
7 Daniel Estevez <daniel@destevez.net>
8
9 Comments, questions and bugreports should be submitted via
10 http://sourceforge.net/projects/gpredict/
11 More details can be found at the project home page:
12
13 http://gpredict.oz9aec.net/
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, visit http://www.fsf.org/
27 */
28
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include "sgpsdp/sgp4sdp4.h"
32 #include "gtk-sat-data.h"
33 #include "sat-log.h"
34 #ifdef HAVE_CONFIG_H
35 #include <build-config.h>
36 #endif
37 #include "orbit-tools.h"
38 #include "time-tools.h"
39 #include "compat.h"
40
41
42 /**
43 * Read TLE data for a given satellite into memory.
44 *
45 * @param catnum The catalog number of the satellite.
46 * @param sat Pointer to a valid sat_t structure.
47 * @return 0 if successfull, 1 if an I/O error occurred,
48 * 2 if the TLE data appears to be bad.
49 *
50 */
gtk_sat_data_read_sat(gint catnum,sat_t * sat)51 gint gtk_sat_data_read_sat(gint catnum, sat_t * sat)
52 {
53 guint errorcode = 0;
54 GError *error = NULL;
55 GKeyFile *data;
56 gchar *filename = NULL, *path = NULL;
57 gchar *tlestr1, *tlestr2, *rawtle;
58
59
60 /* ensure that sat != NULL */
61 g_return_val_if_fail(sat != NULL, 1);
62
63 /* .sat file names */
64 filename = g_strdup_printf("%d.sat", catnum);
65 path = sat_file_name_from_catnum(catnum);
66
67 /* open .sat file */
68 data = g_key_file_new();
69 if (!g_key_file_load_from_file
70 (data, path, G_KEY_FILE_KEEP_COMMENTS, &error))
71 {
72 /* an error occurred */
73 sat_log_log(SAT_LOG_LEVEL_ERROR,
74 _("%s: Failed to load data from %s (%s)"),
75 __func__, path, error->message);
76
77 g_clear_error(&error);
78
79 errorcode = 1;
80 }
81 else
82 {
83 /* read name, nickname, and website */
84 sat->name = g_key_file_get_string(data, "Satellite", "NAME", &error);
85 if (error != NULL)
86 {
87 sat_log_log(SAT_LOG_LEVEL_ERROR,
88 _("%s: Error reading NAME from %s (%s)"),
89 __func__, path, error->message);
90 g_clear_error(&error);
91 sat->name = g_strdup("Error");
92 }
93 sat->nickname =
94 g_key_file_get_string(data, "Satellite", "NICKNAME", &error);
95 if (error != NULL)
96 {
97 sat_log_log(SAT_LOG_LEVEL_INFO,
98 _("%s: Satellite %d has no NICKNAME"),
99 __func__, catnum);
100 g_clear_error(&error);
101 sat->nickname = g_strdup(sat->name);
102 }
103
104 sat->website = g_key_file_get_string(data, "Satellite", "WEBSITE", NULL); /* website may be NULL */
105
106 /* get TLE data */
107 tlestr1 = g_key_file_get_string(data, "Satellite", "TLE1", NULL);
108 if (error != NULL)
109 {
110 sat_log_log(SAT_LOG_LEVEL_ERROR,
111 _("%s: Error reading TLE line 1 from %s (%s)"),
112 __func__, path, error->message);
113 g_clear_error(&error);
114 }
115 tlestr2 = g_key_file_get_string(data, "Satellite", "TLE2", NULL);
116 if (error != NULL)
117 {
118 sat_log_log(SAT_LOG_LEVEL_ERROR,
119 _("%s: Error reading TLE line 2 from %s (%s)"),
120 __func__, path, error->message);
121 g_clear_error(&error);
122 }
123
124 rawtle = g_strconcat(tlestr1, tlestr2, NULL);
125
126 if (!Good_Elements(rawtle))
127 {
128 sat_log_log(SAT_LOG_LEVEL_ERROR,
129 _("%s: TLE data for %d appears to be bad"),
130 __func__, catnum);
131 errorcode = 2;
132 }
133 else
134 {
135 Convert_Satellite_Data(rawtle, &sat->tle);
136 }
137 if (g_key_file_has_key(data, "Satellite", "STATUS", NULL))
138 sat->tle.status =
139 g_key_file_get_integer(data, "Satellite", "STATUS", NULL);
140
141 g_free(tlestr1);
142 g_free(tlestr2);
143 g_free(rawtle);
144
145 /* VERY, VERY important! If not done, some sats
146 will not get initialised, the first time SGP4/SDP4
147 is called. Consequently, the resulting data will
148 be NAN, INF or similar nonsense.
149 For some reason, not even using g_new0 seems to
150 be enough.
151 */
152 sat->flags = 0;
153
154 select_ephemeris(sat);
155
156 /* initialise variable fields */
157 sat->jul_utc = 0.0;
158 sat->tsince = 0.0;
159 sat->az = 0.0;
160 sat->el = 0.0;
161 sat->range = 0.0;
162 sat->range_rate = 0.0;
163 sat->ra = 0.0;
164 sat->dec = 0.0;
165 sat->ssplat = 0.0;
166 sat->ssplon = 0.0;
167 sat->alt = 0.0;
168 sat->velo = 0.0;
169 sat->ma = 0.0;
170 sat->footprint = 0.0;
171 sat->phase = 0.0;
172 sat->aos = 0.0;
173 sat->los = 0.0;
174
175 /* calculate satellite data at epoch */
176 gtk_sat_data_init_sat(sat, NULL);
177 }
178
179 g_free(filename);
180 g_free(path);
181 g_key_file_free(data);
182
183 return errorcode;
184 }
185
186 /**
187 * Initialise satellite data.
188 *
189 * @param sat The satellite to initialise.
190 * @param qth Optional QTH info, use (0,0) if NULL.
191 *
192 * This function calculates the satellite data at t = 0, ie. epoch time
193 * The function is called automatically by gtk_sat_data_read_sat.
194 */
gtk_sat_data_init_sat(sat_t * sat,qth_t * qth)195 void gtk_sat_data_init_sat(sat_t * sat, qth_t * qth)
196 {
197 geodetic_t obs_geodetic;
198 obs_set_t obs_set;
199 geodetic_t sat_geodetic;
200 double jul_utc, age;
201
202 g_return_if_fail(sat != NULL);
203
204 jul_utc = Julian_Date_of_Epoch(sat->tle.epoch); // => tsince = 0.0
205 sat->jul_epoch = jul_utc;
206
207 /* initialise observer location */
208 if (qth != NULL)
209 {
210 obs_geodetic.lon = qth->lon * de2ra;
211 obs_geodetic.lat = qth->lat * de2ra;
212 obs_geodetic.alt = qth->alt / 1000.0;
213 obs_geodetic.theta = 0;
214 }
215 else
216 {
217 obs_geodetic.lon = 0.0;
218 obs_geodetic.lat = 0.0;
219 obs_geodetic.alt = 0.0;
220 obs_geodetic.theta = 0;
221 }
222
223 /* execute computations */
224 if (sat->flags & DEEP_SPACE_EPHEM_FLAG)
225 SDP4(sat, 0.0);
226 else
227 SGP4(sat, 0.0);
228
229 /* scale position and velocity to km and km/sec */
230 Convert_Sat_State(&sat->pos, &sat->vel);
231
232 /* get the velocity of the satellite */
233 Magnitude(&sat->vel);
234 sat->velo = sat->vel.w;
235 Calculate_Obs(jul_utc, &sat->pos, &sat->vel, &obs_geodetic, &obs_set);
236 Calculate_LatLonAlt(jul_utc, &sat->pos, &sat_geodetic);
237
238 while (sat_geodetic.lon < -pi)
239 sat_geodetic.lon += twopi;
240
241 while (sat_geodetic.lon > (pi))
242 sat_geodetic.lon -= twopi;
243
244 sat->az = Degrees(obs_set.az);
245 sat->el = Degrees(obs_set.el);
246 sat->range = obs_set.range;
247 sat->range_rate = obs_set.range_rate;
248 sat->ssplat = Degrees(sat_geodetic.lat);
249 sat->ssplon = Degrees(sat_geodetic.lon);
250 sat->alt = sat_geodetic.alt;
251 sat->ma = Degrees(sat->phase);
252 sat->ma *= 256.0 / 360.0;
253 sat->footprint = 2.0 * xkmper * acos(xkmper / sat->pos.w);
254 age = 0.0;
255 sat->orbit = (long)floor((sat->tle.xno * xmnpda / twopi +
256 age * sat->tle.bstar * ae) * age -
257 (sat->tle.xmo + sat->tle.omegao) / twopi) +
258 sat->tle.revnum;
259
260 /* orbit type */
261 sat->otype = get_orbit_type(sat);
262 }
263
264 /**
265 * Copy satellite data.
266 *
267 * @param source Pointer to the source satellite to copy data from.
268 * @param dest Pointer to the destination satellite to copy data into.
269 * @param qth Pointer to the observer data (needed to initialize sat)
270 *
271 * This function copies the satellite data from a source sat_t structure into
272 * the destination. The function copies the tle_t data and calls gtk_sat_data_inti_sat()
273 * function for initializing the other fields.
274 *
275 */
gtk_sat_data_copy_sat(const sat_t * source,sat_t * dest,qth_t * qth)276 void gtk_sat_data_copy_sat(const sat_t * source, sat_t * dest, qth_t * qth)
277 {
278 guint i;
279
280 g_return_if_fail((source != NULL) && (dest != NULL));
281
282 dest->tle.epoch = source->tle.epoch;
283 dest->tle.epoch_year = source->tle.epoch_year;
284 dest->tle.epoch_day = source->tle.epoch_day;
285 dest->tle.epoch_fod = source->tle.epoch_fod;
286 dest->tle.xndt2o = source->tle.xndt2o;
287 dest->tle.xndd6o = source->tle.xndd6o;
288 dest->tle.bstar = source->tle.bstar;
289 dest->tle.xincl = source->tle.xincl;
290 dest->tle.xnodeo = source->tle.xnodeo;
291 dest->tle.eo = source->tle.eo;
292 dest->tle.omegao = source->tle.omegao;
293 dest->tle.xmo = source->tle.xmo;
294 dest->tle.xno = source->tle.xno;
295 dest->tle.catnr = source->tle.catnr;
296 dest->tle.elset = source->tle.elset;
297 dest->tle.revnum = source->tle.revnum;
298
299 dest->name = g_strdup(source->name);
300 dest->nickname = g_strdup(source->nickname);
301 for (i = 0; i < 9; i++)
302 dest->tle.idesg[i] = source->tle.idesg[i];
303
304 dest->tle.status = source->tle.status;
305 dest->tle.xincl1 = source->tle.xincl1;
306 dest->tle.omegao1 = source->tle.omegao1;
307
308 dest->otype = source->otype;
309
310 /* very important */
311 dest->flags = 0;
312 select_ephemeris(dest);
313
314 /* initialise variable fields */
315 dest->jul_utc = 0.0;
316 dest->tsince = 0.0;
317 dest->az = 0.0;
318 dest->el = 0.0;
319 dest->range = 0.0;
320 dest->range_rate = 0.0;
321 dest->ra = 0.0;
322 dest->dec = 0.0;
323 dest->ssplat = 0.0;
324 dest->ssplon = 0.0;
325 dest->alt = 0.0;
326 dest->velo = 0.0;
327 dest->ma = 0.0;
328 dest->footprint = 0.0;
329 dest->phase = 0.0;
330 dest->aos = 0.0;
331 dest->los = 0.0;
332
333 gtk_sat_data_init_sat(dest, qth);
334 }
335
336 /**
337 * Free satellite data
338 *
339 * @param sat Pointer to the satellite data to free
340 *
341 * This function frees the memory that has been dyunamically allocated
342 * when creating a new satellite object.
343 */
gtk_sat_data_free_sat(sat_t * sat)344 void gtk_sat_data_free_sat(sat_t * sat)
345 {
346 if (!sat)
347 return;
348
349 if (sat->name)
350 {
351 g_free(sat->name);
352 sat->name = NULL;
353 }
354 if (sat->nickname)
355 {
356 g_free(sat->nickname);
357 sat->nickname = NULL;
358 }
359 if (sat->website)
360 {
361 g_free(sat->website);
362 sat->website = NULL;
363 }
364
365 g_free(sat);
366 }
367