/ src / predict-tools.c
predict-tools.c
  1  /*
  2      Gpredict: Real-time satellite tracking and orbit prediction program
  3  
  4      Copyright (C)  2001-2013  Alexandru Csete, OZ9AEC.
  5      Parts are Copyright John A. Magliacane, KD2BD 1991-2003 (indicated below)
  6  
  7      Authors: Alexandru Csete <oz9aec@gmail.com>
  8               John A. Magliacane, KD2BD.
  9               Charles Suprin <hamaa1vs@gmail.com>
 10  	     Daniel Estevez <daniel@destevez.net>
 11  
 12      Comments, questions and bugreports should be submitted via
 13      http://sourceforge.net/projects/gpredict/
 14      More details can be found at the project home page:
 15  
 16              http://gpredict.oz9aec.net/
 17   
 18      This program is free software; you can redistribute it and/or modify
 19      it under the terms of the GNU General Public License as published by
 20      the Free Software Foundation; either version 2 of the License, or
 21      (at your option) any later version.
 22    
 23      This program is distributed in the hope that it will be useful,
 24      but WITHOUT ANY WARRANTY; without even the implied warranty of
 25      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 26      GNU General Public License for more details.
 27    
 28      You should have received a copy of the GNU General Public License
 29      along with this program; if not, visit http://www.fsf.org/
 30  */
 31  
 32  #ifdef HAVE_CONFIG_H
 33  #include <build-config.h>
 34  #endif
 35  
 36  #include <glib.h>
 37  #include <glib/gi18n.h>
 38  
 39  #include "gtk-sat-data.h"
 40  #include "orbit-tools.h"
 41  #include "predict-tools.h"
 42  #include "sat-cfg.h"
 43  #include "sat-log.h"
 44  #include "sgpsdp/sgp4sdp4.h"
 45  #include "time-tools.h"
 46  
 47  static pass_t  *get_pass_engine(sat_t * sat_in, qth_t * qth, gdouble start,
 48                                  gdouble maxdt, gdouble min_el);
 49  
 50  /**
 51   * \brief SGP4SDP4 driver for doing AOS/LOS calculations.
 52   * \param sat Pointer to the satellite data.
 53   * \param qth Pointer to the QTH data.
 54   * \param t The time for calculation (Julian Date)
 55   */
 56  void predict_calc(sat_t * sat, qth_t * qth, gdouble t)
 57  {
 58      obs_set_t       obs_set;
 59      geodetic_t      sat_geodetic;
 60      geodetic_t      obs_geodetic;
 61      double          age;
 62  
 63      obs_geodetic.lon = qth->lon * de2ra;
 64      obs_geodetic.lat = qth->lat * de2ra;
 65      obs_geodetic.alt = qth->alt / 1000.0;
 66      obs_geodetic.theta = 0;
 67  
 68      sat->jul_utc = t;
 69      sat->tsince = (sat->jul_utc - sat->jul_epoch) * xmnpda;
 70  
 71      /* call the norad routines according to the deep-space flag */
 72      if (sat->flags & DEEP_SPACE_EPHEM_FLAG)
 73          SDP4(sat, sat->tsince);
 74      else
 75          SGP4(sat, sat->tsince);
 76  
 77      Convert_Sat_State(&sat->pos, &sat->vel);
 78  
 79      /* get the velocity of the satellite */
 80      Magnitude(&sat->vel);
 81      sat->velo = sat->vel.w;
 82      Calculate_Obs(sat->jul_utc, &sat->pos, &sat->vel, &obs_geodetic, &obs_set);
 83      Calculate_LatLonAlt(sat->jul_utc, &sat->pos, &sat_geodetic);
 84  
 85      while (sat_geodetic.lon < -pi)
 86          sat_geodetic.lon += twopi;
 87  
 88      while (sat_geodetic.lon > (pi))
 89          sat_geodetic.lon -= twopi;
 90  
 91      sat->az = Degrees(obs_set.az);
 92      sat->el = Degrees(obs_set.el);
 93      sat->range = obs_set.range;
 94      sat->range_rate = obs_set.range_rate;
 95      sat->ssplat = Degrees(sat_geodetic.lat);
 96      sat->ssplon = Degrees(sat_geodetic.lon);
 97      sat->alt = sat_geodetic.alt;
 98      sat->ma = Degrees(sat->phase);
 99      sat->ma *= 256.0 / 360.0;
100      sat->phase = Degrees(sat->phase);
101  
102      /* same formulas, but the one from predict is nicer */
103      //sat->footprint = 2.0 * xkmper * acos (xkmper/sat->pos.w);
104      sat->footprint = 12756.33 * acos(xkmper / (xkmper + sat->alt));
105      age = sat->jul_utc - sat->jul_epoch;
106      sat->orbit = (long)floor((sat->tle.xno * xmnpda / twopi +
107                                age * sat->tle.bstar * ae) * age +
108                               (sat->tle.xmo + sat->tle.omegao) / twopi)
109        - (long)floor((sat->tle.xmo + sat->tle.omegao) / twopi)
110        + sat->tle.revnum ;
111  }
112  
113  /**
114   * \brief Find the AOS time of the next pass.
115   * \author Alexandru Csete, OZ9AEC
116   * \author John A. Magliacane, KD2BD
117   * \param sat Pointer to the satellite data.
118   * \param qth Pointer to the QTH data.
119   * \param start The time where calculation should start.
120   * \param maxdt The upper time limit in days (0.0 = no limit)
121   * \return The time of the next AOS or 0.0 if the satellite has no AOS.
122   *
123   * This function finds the time of AOS for the first coming pass taking place
124   * no earlier that start.
125   * If the satellite is currently within range, the function first calls
126   * find_los to get the next LOS time. Then the calculations are done using
127   * the new start time.
128   */
129  gdouble find_aos(sat_t * sat, qth_t * qth, gdouble start, gdouble maxdt)
130  {
131      gdouble         t = start;
132      gdouble         aostime = 0.0;
133  
134      /* make sure current sat values are in sync with the time */
135      predict_calc(sat, qth, start);
136  
137      /* check whether satellite has aos */
138      if (!has_aos(sat, qth))
139          return 0.0;
140  
141      if (sat->el > 0.0)
142          t = find_los(sat, qth, start, maxdt) + 0.014;   // +20 min
143  
144      /* invalid time (potentially returned by find_los) */
145      if (t < 0.1)
146          return 0.0;
147  
148      /* update satellite data */
149      predict_calc(sat, qth, t);
150  
151      /* use upper time limit */
152      if (maxdt > 0.0)
153      {
154  
155          /* coarse time steps */
156          while ((sat->el < -1.0) && (t <= (start + maxdt)))
157          {
158              t -= 0.00035 * (sat->el * ((sat->alt / 8400.0) + 0.46) - 2.0);
159              predict_calc(sat, qth, t);
160          }
161  
162          /* fine steps */
163          while ((aostime == 0.0) && (t <= (start + maxdt)))
164          {
165  
166              if (fabs(sat->el) < 0.005)
167              {
168                  aostime = t;
169              }
170              else
171              {
172                  t -= sat->el * sqrt(sat->alt) / 530000.0;
173                  predict_calc(sat, qth, t);
174              }
175  
176          }
177  
178      }
179      /* don't use upper time limit */
180      else
181      {
182          /* coarse time steps */
183          while (sat->el < -1.0)
184          {
185              t -= 0.00035 * (sat->el * ((sat->alt / 8400.0) + 0.46) - 2.0);
186              predict_calc(sat, qth, t);
187          }
188  
189          /* fine steps */
190          while (aostime == 0.0)
191          {
192  
193              if (fabs(sat->el) < 0.005)
194              {
195                  aostime = t;
196              }
197              else
198              {
199                  t -= sat->el * sqrt(sat->alt) / 530000.0;
200                  predict_calc(sat, qth, t);
201              }
202          }
203      }
204  
205      return aostime;
206  }
207  
208  /**
209   * \brief Find the LOS time of the next pass.
210   * \author Alexandru Csete, OZ9AEC
211   * \author John A. Magliacane, KD2BD
212   * \param sat Pointer to the satellite data.
213   * \param qth Pointer to the QTH data.
214   * \param start The time where calculation should start.
215   * \param maxdt The upper time limit in days (0.0 = no limit)
216   * \return The time of the next LOS or 0.0 if the satellite has no LOS.
217   *
218   * This function finds the time of LOS for the first coming pass taking place
219   * no earlier that start.
220   * If the satellite is currently out of range, the function first calls
221   * find_aos to get the next AOS time. Then the calculations are done using
222   * the new start time.
223   * The function has a built-in watchdog to ensure that we don't end up in
224   * lengthy loops.
225   */
226  gdouble find_los(sat_t * sat, qth_t * qth, gdouble start, gdouble maxdt)
227  {
228      gdouble         t = start;
229      gdouble         lostime = 0.0;
230      gdouble         eltemp;
231  
232      predict_calc(sat, qth, start);
233  
234      /* check whether satellite has aos */
235      if (!has_aos(sat, qth))
236      {
237          return 0.0;
238      }
239  
240      if (sat->el < 0.0)
241          t = find_aos(sat, qth, start, maxdt) + 0.001;   // +1.5 min
242  
243      /* invalid time (potentially returned by find_aos) */
244      if (t < 0.01)
245          return 0.0;
246  
247      /* update satellite data */
248      predict_calc(sat, qth, t);
249  
250      /* use upper time limit */
251      if (maxdt > 0.0)
252      {
253          /* coarse steps */
254          while ((sat->el >= 1.0) && (t <= (start + maxdt)))
255          {
256              t += cos((sat->el - 1.0) * de2ra) * sqrt(sat->alt) / 25000.0;
257              predict_calc(sat, qth, t);
258          }
259  
260          /* fine steps */
261          while ((lostime == 0.0) && (t <= (start + maxdt)))
262          {
263              t += sat->el * sqrt(sat->alt) / 502500.0;
264              predict_calc(sat, qth, t);
265  
266              if (fabs(sat->el) < 0.005)
267              {
268                  /* Two things are true at LOS time, the elevation is a zero and
269                     sat is descending. This checks that those two are true. */
270                  eltemp = sat->el;
271  
272                  /* check elevation 1 second earlier */
273                  predict_calc(sat, qth, t - 1.0 / 86400.0);
274  
275                  if (sat->el > eltemp)
276                      lostime = t;
277              }
278          }
279      }
280      /* don't use upper limit */
281      else
282      {
283          /* coarse steps */
284          while (sat->el >= 1.0)
285          {
286              t += cos((sat->el - 1.0) * de2ra) * sqrt(sat->alt) / 25000.0;
287              predict_calc(sat, qth, t);
288          }
289  
290          /* fine steps */
291          while (lostime == 0.0)
292          {
293              t += sat->el * sqrt(sat->alt) / 502500.0;
294              predict_calc(sat, qth, t);
295  
296              if (fabs(sat->el) < 0.005)
297              {
298                  /* two things are true at LOS time
299                     The elevation is a zero and descending.
300                     This checks that those two are true.
301                   */
302                  eltemp = sat->el;
303  
304                  /*check elevation 1 second earlier */
305                  predict_calc(sat, qth, t - 1.0 / 86400.0);
306  
307                  if (sat->el > eltemp)
308                      lostime = t;
309              }
310          }
311      }
312  
313      return lostime;
314  }
315  
316  /**
317   * \brief Find AOS time of current pass.
318   * \param sat The satellite to find AOS for.
319   * \param qth The ground station.
320   * \param start Start time, prefereably now.
321   * \return The time of the previous AOS or 0.0 if the satellite has no AOS.
322   *
323   * This function can be used to find the AOS time in the past of the
324   * current pass.
325   */
326  gdouble find_prev_aos(sat_t * sat, qth_t * qth, gdouble start)
327  {
328      gdouble         aostime = start;
329  
330      /* make sure current sat values are in sync with the time */
331      predict_calc(sat, qth, start);
332  
333      /* check whether satellite has aos */
334      if (!has_aos(sat, qth))
335      {
336          return 0.0;
337      }
338  
339      while (sat->el >= 0.0)
340      {
341          aostime -= 0.0005;      // 0.75 min
342          predict_calc(sat, qth, aostime);
343      }
344  
345      return aostime;
346  }
347  
348  /**
349   * \brief Predict the next pass.
350   * \param sat Pointer to the satellite data.
351   * \param qth Pointer to the observer data.
352   * \param maxdt The maximum number of days to look ahead.
353   * \return Pointer newly allocated pass_t structure that should be freed
354   *         with free_pass when no longer needed, or NULL if no pass can be
355   *         found.
356   *
357   * This function simply wraps the get_pass function using the current time
358   * as parameter.
359   *
360   * \note the data in sat will be corrupt (future) and must be refreshed
361   *       by the caller, if the caller will need it later on (eg. if the caller
362   *       is GtkSatList).
363   */
364  pass_t         *get_next_pass(sat_t * sat, qth_t * qth, gdouble maxdt)
365  {
366      gdouble         now;
367  
368      /* get the current time and call the get_pass function */
369      now = get_current_daynum();
370  
371      return get_pass(sat, qth, now, maxdt);
372  }
373  
374  /**
375   * \brief Predict upcoming passes starting now
376   * \param sat Pointer to the satellite data.
377   * \param qth Pointer to the observer data.
378   * \param maxdt The maximum number of days to look ahead.
379   * \param num The number of passes to predict.
380   * \return A singly linked list of pass_t structures or NULL if
381   *         there was an error.
382   *
383   * This function simply wraps the get_passes function using the
384   * current time as parameter.
385   *
386   * \note the data in sat will be corrupt (future) and must be refreshed
387   *       by the caller, if the caller will need it later on (eg. if the caller
388   *       is GtkSatList).
389   */
390  GSList         *get_next_passes(sat_t * sat, qth_t * qth, gdouble maxdt,
391                                  guint num)
392  {
393      gdouble         now;
394  
395      /* get the current time and call the get_pass function */
396      now = get_current_daynum();
397  
398      return get_passes(sat, qth, now, maxdt, num);
399  }
400  
401  /**
402   * \brief Predict first pass after a certain time.
403   * \param sat Pointer to the satellite data.
404   * \param qth Pointer to the location data.
405   * \param start Starting time.
406   * \param maxdt The maximum number of days to look ahead (0 for no limit).
407   * \return Pointer to a newly allocated pass_t structure or NULL if
408   *         there was an error.
409   * 
410   *   This function assumes that you want a pass that achieves the 
411   *   minimum elevation of is configured for.
412   */
413  pass_t *get_pass(sat_t * sat_in, qth_t * qth, gdouble start, gdouble maxdt)
414  {
415      int      min_ele = sat_cfg_get_int(SAT_CFG_INT_PRED_MIN_EL);
416  
417      if (min_ele == 0)
418          min_ele = 1;
419  
420      return get_pass_engine(sat_in, qth, start, maxdt, min_ele);
421  }
422  
423  /**
424   * \brief Predict first pass after a certain time ignoring the min elevation.
425   * \param sat Pointer to the satellite data.
426   * \param qth Pointer to the location data.
427   * \param start Starting time.
428   * \param maxdt The maximum number of days to look ahead (0 for no limit).
429   * \return Pointer to a newly allocated pass_t structure or NULL if
430   *         there was an error.
431   * This function assumes that you want a pass that achieves the 
432   * minimum elevation of is configured for.
433   */
434  pass_t         *get_pass_no_min_el(sat_t * sat_in, qth_t * qth, gdouble start,
435                                     gdouble maxdt)
436  {
437      return get_pass_engine(sat_in, qth, start, maxdt, 0.0);
438  }
439  
440  /**
441   * \brief Predict first pass after a certain time.
442   * \param sat Pointer to the satellite data.
443   * \param qth Pointer to the location data.
444   * \param start Starting time.
445   * \param maxdt The maximum number of days to look ahead (0 for no limit).
446   * \return Pointer to a newly allocated pass_t structure or NULL if
447   *         there was an error.
448   *
449   * This function will find the first upcoming pass with AOS no earlier than
450   * t = start and no later than t = (start+maxdt).
451   *
452   * \note For no time limit use maxdt = 0.0
453   *
454   * \note the data in sat will be corrupt (future) and must be refreshed
455   *       by the caller, if the caller will need it later on (eg. if the caller
456   *       is GtkSatList).
457   *
458   * \note Prepending to a singly linked list is much faster than appending.
459   *       Therefore, the elements are prepended whereafter the GSList is
460   *       reversed
461   */
462  static pass_t  *get_pass_engine(sat_t * sat_in, qth_t * qth, gdouble start,
463                                  gdouble maxdt, gdouble min_el)
464  {
465      gdouble         aos = 0.0;  /* time of AOS */
466      gdouble         tca = 0.0;  /* time of TCA */
467      gdouble         los = 0.0;  /* time of LOS */
468      gdouble         dt = 0.0;   /* time diff */
469      gdouble         step = 0.0; /* time step */
470      gdouble         t0 = start;
471      gdouble         t;          /* current time counter */
472      gdouble         tres = 0.0; /* required time resolution */
473      gdouble         max_el = 0.0;       /* maximum elevation */
474      pass_t         *pass = NULL;
475      pass_detail_t  *detail = NULL;
476      gboolean        done = FALSE;
477      guint           iter = 0;   /* number of iterations */
478      sat_t          *sat, sat_working;
479  
480      /* FIXME: watchdog */
481  
482      /*copy sat_in to a working structure */
483      sat = memcpy(&sat_working, sat_in, sizeof(sat_t));
484  
485      /* get time resolution; sat-cfg stores it in seconds */
486      tres = sat_cfg_get_int(SAT_CFG_INT_PRED_RESOLUTION) / 86400.0;
487  
488      /* loop until we find a pass with elevation > SAT_CFG_INT_PRED_MIN_EL
489         or we run out of time
490         FIXME: we should have a safety break
491       */
492      while (!done)
493      {
494          /* Find los of next pass or of current pass */
495          los = find_los(sat, qth, t0, maxdt);    // See if a pass is ongoing
496          aos = find_aos(sat, qth, t0, start + maxdt - t0);
497  
498          if (aos > los)
499              // los is from an currently happening pass, find previous aos
500              aos = find_prev_aos(sat, qth, t0);
501  
502          /* aos = 0.0 means no aos */
503          if (aos == 0.0)
504              done = TRUE;
505  
506          /* check whether we are within time limits;
507             maxdt = 0 mean no time limit.
508           */
509          else if ((maxdt > 0.0) && (aos > (start + maxdt)))
510          {
511              done = TRUE;
512          }
513          else
514          {
515              //los = find_los (sat, qth, aos + 0.001, maxdt); // +1.5 min later
516              dt = los - aos;
517  
518              /* get time step, which will give us the max number of entries */
519              step = dt / sat_cfg_get_int(SAT_CFG_INT_PRED_NUM_ENTRIES);
520  
521              /* but if this is smaller than the required resolution
522                 we go with the resolution
523               */
524              if (step < tres)
525                  step = tres;
526  
527              /* create a pass_t entry; FIXME: g_try_new in 2.8 */
528              pass = g_new(pass_t, 1);
529  
530              pass->aos = aos;
531              pass->los = los;
532              pass->max_el = 0.0;
533              pass->aos_az = 0.0;
534              pass->los_az = 0.0;
535              pass->maxel_az = 0.0;
536              pass->vis[0] = '-';
537              pass->vis[1] = '-';
538              pass->vis[2] = '-';
539              pass->vis[3] = 0;
540              pass->satname = g_strdup(sat->nickname);
541              pass->details = NULL;
542              /*copy qth data into the pass for later comparisons */
543              qth_small_save(qth, &(pass->qth_comp));
544  
545              /* iterate over each time step */
546              for (t = pass->aos; t <= pass->los; t += step)
547              {
548  
549                  /* calculate satellite data */
550                  predict_calc(sat, qth, t);
551  
552                  /* in the first iter we want to store
553                     pass->aos_az
554                   */
555                  if (t == pass->aos)
556                  {
557                      pass->aos_az = sat->az;
558                      pass->orbit = sat->orbit;
559                  }
560  
561                  /* append details to sat->details */
562                  detail = g_new(pass_detail_t, 1);
563                  detail->time = t;
564                  detail->pos.x = sat->pos.x;
565                  detail->pos.y = sat->pos.y;
566                  detail->pos.z = sat->pos.z;
567                  detail->pos.w = sat->pos.w;
568                  detail->vel.x = sat->vel.x;
569                  detail->vel.y = sat->vel.y;
570                  detail->vel.z = sat->vel.z;
571                  detail->vel.w = sat->vel.w;
572                  detail->velo = sat->velo;
573                  detail->az = sat->az;
574                  detail->el = sat->el;
575                  detail->range = sat->range;
576                  detail->range_rate = sat->range_rate;
577                  detail->lat = sat->ssplat;
578                  detail->lon = sat->ssplon;
579                  detail->alt = sat->alt;
580                  detail->ma = sat->ma;
581                  detail->phase = sat->phase;
582                  detail->footprint = sat->footprint;
583                  detail->orbit = sat->orbit;
584                  detail->vis = get_sat_vis(sat, qth, t);
585  
586                  /* also store visibility "bit" */
587                  switch (detail->vis)
588                  {
589                  case SAT_VIS_VISIBLE:
590                      pass->vis[0] = 'V';
591                      break;
592                  case SAT_VIS_DAYLIGHT:
593                      pass->vis[1] = 'D';
594                      break;
595                  case SAT_VIS_ECLIPSED:
596                      pass->vis[2] = 'E';
597                      break;
598                  default:
599                      break;
600                  }
601  
602                  pass->details = g_slist_prepend(pass->details, detail);
603  
604                  /* store elevation if greater than the
605                     previously stored one
606                   */
607                  if (sat->el > max_el)
608                  {
609                      max_el = sat->el;
610                      tca = t;
611                      pass->maxel_az = sat->az;
612                  }
613  
614                  /*     g_print ("TIME: %f\tAZ: %f\tEL: %f (MAX: %f)\n", */
615                  /*           t, sat->az, sat->el, max_el); */
616              }
617  
618              pass->details = g_slist_reverse(pass->details);
619  
620              /* calculate satellite data */
621              predict_calc(sat, qth, pass->los);
622              /* store los_az, max_el and tca */
623              pass->los_az = sat->az;
624              pass->max_el = max_el;
625              pass->tca = tca;
626  
627              /* check whether this pass is good */
628              if (max_el >= min_el)
629              {
630                  done = TRUE;
631              }
632              else
633              {
634                  done = FALSE;
635                  t0 = los + 0.014;       // +20 min
636                  free_pass(pass);
637                  pass = NULL;
638              }
639  
640              iter++;
641          }
642      }
643  
644      return pass;
645  }
646  
647  /**
648   * Predict passes after a certain time.
649   *
650   * This function calculates num upcoming passes with AOS no earlier
651   * than t = start and not later that t = (start+maxdt). The function will
652   * repeatedly call get_pass until the number of predicted passes is equal to
653   * num, the time has reached limit or the get_pass function returns NULL.
654   *
655   * \note For no time limit use maxdt = 0.0
656   *
657   * \note the data in sat will be corrupt (future) and must be refreshed
658   *       by the caller, if the caller will need it later on (eg. if the caller
659   *       is GtkSatList).
660   *
661   * \note Prepending to a singly linked list is much faster than appending.
662   *       Therefore, the elements are prepended whereafter the GSList is
663   *       reversed
664   */
665  GSList         *get_passes(sat_t * sat, qth_t * qth, gdouble start,
666                             gdouble maxdt, guint num)
667  {
668      GSList         *passes = NULL;
669      pass_t         *pass = NULL;
670      guint           i;
671      gdouble         t;
672  
673      /* if no number has been specified
674         set it to something big */
675      if (num == 0)
676          num = 100;
677  
678      t = start;
679  
680      for (i = 0; i < num; i++)
681      {
682          pass = get_pass(sat, qth, t, maxdt);
683  
684          if (pass != NULL)
685          {
686              passes = g_slist_prepend(passes, pass);
687              t = pass->los + 0.014;      // +20 min
688  
689              /* if maxdt > 0.0 check whether we have reached t = start+maxdt
690                 if yes finish predictions
691               */
692              if ((maxdt > 0.0) && (t >= (start + maxdt)))
693              {
694                  i = num;
695              }
696          }
697          else
698          {
699              /* we can't get any more passes */
700              i = num;
701          }
702  
703      }
704  
705      if (passes != NULL)
706          passes = g_slist_reverse(passes);
707  
708      sat_log_log(SAT_LOG_LEVEL_INFO,
709                  _("%s: Found %d passes for %s in time window [%f;%f]"),
710                  __func__, g_slist_length(passes), sat->nickname, start,
711                  start + maxdt);
712  
713      return passes;
714  }
715  
716  pass_t         *copy_pass(pass_t * pass)
717  {
718      pass_t         *new;
719  
720      new = g_try_new(pass_t, 1);
721  
722      if (new != NULL)
723      {
724          new->aos = pass->aos;
725          new->los = pass->los;
726          new->tca = pass->tca;
727          new->max_el = pass->max_el;
728          new->aos_az = pass->aos_az;
729          new->los_az = pass->los_az;
730          new->orbit = pass->orbit;
731          new->maxel_az = pass->maxel_az;
732          new->vis[0] = pass->vis[0];
733          new->vis[1] = pass->vis[1];
734          new->vis[2] = pass->vis[2];
735          new->vis[3] = pass->vis[3];
736          new->details = copy_pass_details(pass->details);
737  
738          if (pass->satname != NULL)
739              new->satname = g_strdup(pass->satname);
740          else
741              new->satname = NULL;
742      }
743  
744      return new;
745  }
746  
747  GSList         *copy_pass_details(GSList * details)
748  {
749      GSList         *new = NULL;
750      guint           i, n;
751  
752      n = g_slist_length(details);
753      for (i = 0; i < n; i++)
754      {
755          new = g_slist_prepend(new,
756                                copy_pass_detail(PASS_DETAIL
757                                                 (g_slist_nth_data
758                                                  (details, i))));
759      }
760  
761      new = g_slist_reverse(new);
762  
763      return new;
764  }
765  
766  pass_detail_t  *copy_pass_detail(pass_detail_t * detail)
767  {
768      pass_detail_t  *new;
769  
770      /* create a pass_t entry; FIXME: g_try_new in 2.8 */
771      new = g_new(pass_detail_t, 1);
772  
773      new->time = detail->time;
774      new->pos.x = detail->pos.x;
775      new->pos.y = detail->pos.y;
776      new->pos.z = detail->pos.z;
777      new->pos.w = detail->pos.w;
778      new->vel.x = detail->vel.x;
779      new->vel.y = detail->vel.y;
780      new->vel.z = detail->vel.z;
781      new->vel.w = detail->vel.w;
782      new->velo = detail->velo;
783      new->az = detail->az;
784      new->el = detail->el;
785      new->range = detail->range;
786      new->range_rate = detail->range_rate;
787      new->lat = detail->lat;
788      new->lon = detail->lon;
789      new->alt = detail->alt;
790      new->ma = detail->ma;
791      new->phase = detail->phase;
792      new->footprint = detail->footprint;
793      new->orbit = detail->orbit;
794      new->vis = detail->vis;
795  
796      return new;
797  }
798  
799  void free_pass(pass_t * pass)
800  {
801      if (pass != NULL)
802      {
803          free_pass_details(pass->details);
804  
805          if (pass->satname != NULL)
806          {
807              g_free(pass->satname);
808              pass->satname = NULL;
809          }
810  
811          g_free(pass);
812          pass = NULL;
813      }
814  }
815  
816  /** \brief Free a list of passes. */
817  void free_passes(GSList * passes)
818  {
819      guint           n, i;
820      gpointer        pass;
821  
822      n = g_slist_length(passes);
823  
824      for (i = 0; i < n; i++)
825      {
826          pass = g_slist_nth_data(passes, i);
827  
828          /* free element data */
829          free_pass(PASS(pass));
830      }
831  
832      /* now free the list elements */
833      g_slist_free(passes);
834      passes = NULL;
835  }
836  
837  /**
838   * \brief Free a pass detail structure.
839   *
840   * This function is not rarely useful except for the
841   * free_pass function.
842   */
843  void free_pass_detail(pass_detail_t * detail)
844  {
845      g_free(detail);
846      detail = NULL;
847  }
848  
849  /** Free the whole list of details. */
850  void free_pass_details(GSList * details)
851  {
852      guint           n, i;
853      gpointer        detail;
854  
855      n = g_slist_length(details);
856  
857      for (i = 0; i < n; i++)
858      {
859  
860          detail = g_slist_nth_data(details, i);
861  
862          /* free element data */
863          free_pass_detail(PASS_DETAIL(detail));
864      }
865  
866      /* free list elements */
867      g_slist_free(details);
868      details = NULL;
869  }
870  
871  /**
872   * \brief Get current pass.
873   * \param sat Pointer to the satellite data.
874   * \param qth Pointer to the QTH data.
875   * \param start Time to start calculations; use 0.0 for now.
876   * \return Pointer to a newly allocated pass_t structure or NULL if
877   *         there was an error.
878   *
879   * Assuming that sat->el > 0.0 this function calculates the details of the
880   * current pass from AOS time to LOS time.
881   * First the function goes back in time to before the AOS, then it calls
882   * the get_pass_no_min_el function to get the details of the current pass
883   * disregarding any minimum elevation requirements.
884   *
885   * \note The start parameter has been introduced to allow correct use of this
886   *       function in non-realtime cases.
887   */
888  pass_t         *get_current_pass(sat_t * sat_in, qth_t * qth, gdouble start)
889  {
890      gdouble         t, t0;
891      gdouble         el0;
892      sat_t          *sat, sat_working;
893      pass_t         *pass;
894  
895      /*copy sat_in to a working structure */
896      sat = memcpy(&sat_working, sat_in, sizeof(sat_t));
897  
898      if (start > 0.0)
899          t = start;
900      else
901          t = get_current_daynum();
902      predict_calc(sat, qth, t);
903  
904      /*save initial conditions for later comparison */
905      t0 = t;
906      el0 = sat->el;
907  
908      /* check whether satellite has aos */
909      if (!has_aos(sat, qth))
910          return NULL;
911  
912      /* find a time before AOS */
913      while (sat->el > 0.0)
914      {
915          predict_calc(sat, qth, t);
916          t -= 0.007;             // +10 min
917      }
918  
919      pass = get_pass_no_min_el(sat, qth, t, 0.0);
920      if (el0 > 0.0)
921      {
922          /* this function is only specified if the elevation 
923             is greater than zero at the time it is called */
924          if (pass)
925          {
926              if (pass->aos > t0)
927                  sat_log_log(SAT_LOG_LEVEL_ERROR,
928                              _
929                              ("%s: Returning a pass for %s that starts after the seeded time."),
930                              __func__, sat->nickname);
931  
932              if (pass->los < t0)
933                  sat_log_log(SAT_LOG_LEVEL_ERROR,
934                              _
935                              ("%s: Returning a pass for %s that ends before the seeded time."),
936                              __func__, sat->nickname);
937          }
938      }
939  
940      return pass;
941  }