gpredict/src/predict-tools.c

1027 lines
25 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
Gpredict: Real-time satellite tracking and orbit prediction program
Copyright (C) 2001-2007 Alexandru Csete, OZ9AEC.
Parts are Copyright John A. Magliacane, KD2BD 1991-2003 (indicated below)
Authors: Alexandru Csete <oz9aec@gmail.com>
John A. Magliacane, KD2BD.
Comments, questions and bugreports should be submitted via
http://sourceforge.net/projects/groundstation/
More details can be found at the project home page:
http://groundstation.sourceforge.net/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, visit http://www.fsf.org/
*/
#include <glib.h>
#include <glib/gi18n.h>
#include "sgpsdp/sgp4sdp4.h"
#ifdef HAVE_CONFIG_H
# include <build-config.h>
#endif
#include "gtk-sat-data.h"
#include "time-tools.h"
#include "sat-cfg.h"
#include "orbit-tools.h"
#include "predict-tools.h"
/** \brief SGP4SDP4 driver for doing AOS/LOS calculations.
* \param sat Pointer to the satellite data.
* \param qth Pointer to the QTH data.
* \param t The time for calculation (Julian Date)
*
*/
void
predict_calc (sat_t *sat, qth_t *qth, gdouble t)
{
obs_set_t obs_set;
geodetic_t sat_geodetic;
geodetic_t obs_geodetic;
double age;
obs_geodetic.lon = qth->lon * de2ra;
obs_geodetic.lat = qth->lat * de2ra;
obs_geodetic.alt = qth->alt / 1000.0;
obs_geodetic.theta = 0;
sat->jul_utc = t;
sat->tsince = (sat->jul_utc - sat->jul_epoch) * xmnpda;
/* call the norad routines according to the deep-space flag */
if (sat->flags & DEEP_SPACE_EPHEM_FLAG)
SDP4 (sat, sat->tsince);
else
SGP4 (sat, sat->tsince);
Convert_Sat_State (&sat->pos, &sat->vel);
/* get the velocity of the satellite */
Magnitude (&sat->vel);
sat->velo = sat->vel.w;
Calculate_Obs (sat->jul_utc, &sat->pos, &sat->vel, &obs_geodetic, &obs_set);
Calculate_LatLonAlt (sat->jul_utc, &sat->pos, &sat_geodetic);
while (sat_geodetic.lon < -pi)
sat_geodetic.lon += twopi;
while (sat_geodetic.lon > (pi))
sat_geodetic.lon -= twopi;
sat->az = Degrees (obs_set.az);
sat->el = Degrees (obs_set.el);
sat->range = obs_set.range;
sat->range_rate = obs_set.range_rate;
sat->ssplat = Degrees (sat_geodetic.lat);
sat->ssplon = Degrees (sat_geodetic.lon);
sat->alt = sat_geodetic.alt;
sat->ma = Degrees (sat->phase);
sat->ma *= 256.0/360.0;
sat->phase = Degrees (sat->phase);
/* same formulas, but the one from predict is nicer */
//sat->footprint = 2.0 * xkmper * acos (xkmper/sat->pos.w);
sat->footprint = 12756.33 * acos (xkmper / (xkmper+sat->alt));
age = sat->jul_utc - sat->jul_epoch;
sat->orbit = (long) floor((sat->tle.xno * xmnpda/twopi +
age * sat->tle.bstar * ae) * age +
sat->tle.xmo/twopi) + sat->tle.revnum - 1;
}
/** \brief Find the AOS time of the next pass.
* \author Alexandru Csete, OZ9AEC
* \author John A. Magliacane, KD2BD
* \param sat Pointer to the satellite data.
* \param qth Pointer to the QTH data.
* \param start The time where calculation should start.
* \param maxdt The upper time limit in days (0.0 = no limit)
* \return The time of the next AOS or 0.0 if the satellite has no AOS.
*
* This function finds the time of AOS for the first coming pass taking place
* no earlier that start.
* If the satellite is currently within range, the function first calls
* find_los to get the next LOS time. Then the calculations are done using
* the new start time.
*
*/
gdouble
find_aos (sat_t *sat, qth_t *qth, gdouble start, gdouble maxdt)
{
gdouble t = start;
gdouble aostime = 0.0;
/* make sure current sat values are
in sync with the time
*/
predict_calc (sat, qth, start);
/* check whether satellite has aos */
if ((sat->otype == ORBIT_TYPE_GEO) ||
(sat->otype == ORBIT_TYPE_DECAYED) ||
!has_aos (sat, qth)) {
return 0.0;
}
if (sat->el > 0.0)
t = find_los (sat, qth, start, maxdt) + 0.014; // +20 min
/* invalid time (potentially returned by find_los) */
if (t < 0.014)
return 0.0;
/* update satellite data */
predict_calc (sat, qth, t);
/* use upper time limit */
if (maxdt > 0.0) {
/* coarse time steps */
while ((sat->el < -1.0) && (t <= (start + maxdt))) {
t -= 0.00035 * (sat->el * ((sat->alt / 8400.0) + 0.46) - 2.0);
predict_calc (sat, qth, t);
}
/* fine steps */
while ((aostime == 0.0) && (t <= (start + maxdt))) {
if (fabs (sat->el) < 0.005) {
aostime = t;
}
else {
t -= sat->el * sqrt (sat->alt) / 530000.0;
predict_calc (sat, qth, t);
}
}
}
/* don't use upper time limit */
else {
/* coarse time steps */
while (sat->el < -1.0) {
t -= 0.00035 * (sat->el * ((sat->alt / 8400.0) + 0.46) - 2.0);
predict_calc (sat, qth, t);
}
/* fine steps */
while (aostime == 0.0) {
if (fabs (sat->el) < 0.005) {
aostime = t;
}
else {
t -= sat->el * sqrt (sat->alt) / 530000.0;
predict_calc (sat, qth, t);
}
}
}
return aostime;
}
/** \brief Find the LOS time of the next pass.
* \author Alexandru Csete, OZ9AEC
* \author John A. Magliacane, KD2BD
* \param sat Pointer to the satellite data.
* \param qth Pointer to the QTH data.
* \param start The time where calculation should start.
* \param maxdt The upper time limit in days (0.0 = no limit)
* \return The time of the next LOS or 0.0 if the satellite has no LOS.
*
* This function finds the time of LOS for the first coming pass taking place
* no earlier that start.
* If the satellite is currently out of range, the function first calls
* find_aos to get the next AOS time. Then the calculations are done using
* the new start time.
* The function has a built-in watchdog to ensure that we don't end up in
* lengthy loops.
*
*/
gdouble
find_los (sat_t *sat, qth_t *qth, gdouble start, gdouble maxdt)
{
gdouble t = start;
gdouble lostime = 0.0;
predict_calc (sat, qth, start);
/* check whether satellite has aos */
if ((sat->otype == ORBIT_TYPE_GEO) ||
(sat->otype == ORBIT_TYPE_DECAYED) ||
!has_aos (sat, qth)) {
return 0.0;
}
if (sat->el < 0.0)
t = find_aos (sat, qth, start, maxdt) + 0.001; // +1.5 min
/* invalid time (potentially returned by find_aos) */
if (t < 0.01)
return 0.0;
/* update satellite data */
predict_calc (sat, qth, t);
/* use upper time limit */
if (maxdt > 0.0) {
/* coarse steps */
while ((sat->el >= 1.0) && (t <= (start + maxdt))) {
t += cos((sat->el - 1.0) * de2ra) * sqrt(sat->alt) / 25000.0;
predict_calc (sat, qth, t);
}
/* fine steps */
while ((lostime == 0.0) && (t <= (start + maxdt))) {
t += sat->el * sqrt(sat->alt)/502500.0;
predict_calc (sat, qth, t);
if (fabs(sat->el) < 0.005)
lostime = t;
}
}
/* don't use upper limit */
else {
/* coarse steps */
while (sat->el >= 1.0) {
t += cos((sat->el - 1.0) * de2ra) * sqrt(sat->alt) / 25000.0;
predict_calc (sat, qth, t);
}
/* fine steps */
while (lostime == 0.0) {
t += sat->el * sqrt(sat->alt)/502500.0;
predict_calc (sat, qth, t);
if (fabs(sat->el) < 0.005)
lostime = t;
}
}
return lostime;
}
/** \brief Find AOS time of current pass.
* \param sat The satellite to find AOS for.
* \param qth The ground station.
* \param start Start time, prefereably now.
* \return The time of the previous AOS or 0.0 if the satellite has no AOS.
*
* This function can be used to find the AOS time in the past of the
* current pass.
*/
gdouble
find_prev_aos (sat_t *sat, qth_t *qth, gdouble start)
{
gdouble aostime = start;
/* make sure current sat values are
in sync with the time
*/
predict_calc (sat, qth, start);
/* check whether satellite has aos */
if ((sat->otype == ORBIT_TYPE_GEO) ||
(sat->otype == ORBIT_TYPE_DECAYED) ||
!has_aos (sat, qth)) {
return 0.0;
}
while (sat->el >= 0.0) {
aostime -= 0.0005; // 0.75 min
predict_calc (sat, qth, aostime);
}
return aostime;
}
/** \brief Predict the next pass.
* \param sat Pointer to the satellite data.
* \param qth Pointer to the observer data.
* \param maxdt The maximum number of days to look ahead.
* \return Pointer newly allocated pass_t structure that should be freed
* with free_pass when no longer needed, or NULL if no pass can be
* found.
*
* This function simply wraps the get_pass function using the current time
* as parameter.
*
* \note the data in sat will be corrupt (future) and must be refreshed
* by the caller, if the caller will need it later on (eg. if the caller
* is GtkSatList).
*
*/
pass_t *
get_next_pass (sat_t *sat, qth_t *qth, gdouble maxdt)
{
gdouble now;
/* get the current time and call
the get_pass function */
now = get_current_daynum ();
return get_pass (sat, qth, now, maxdt);
}
/** \brief Predict upcoming passes starting now
* \param sat Pointer to the satellite data.
* \param qth Pointer to the observer data.
* \param maxdt The maximum number of days to look ahead.
* \param num The number of passes to predict.
* \return A singly linked list of pass_t structures or NULL if
* there was an error.
*
* This function simply wraps the get_passes function using the
* current time as parameter.
*
* \note the data in sat will be corrupt (future) and must be refreshed
* by the caller, if the caller will need it later on (eg. if the caller
* is GtkSatList).
*/
GSList *
get_next_passes (sat_t *sat, qth_t *qth, gdouble maxdt, guint num)
{
gdouble now;
/* get the current time and call
the get_pass function */
now = get_current_daynum ();
return get_passes (sat, qth, now, maxdt, num);
}
/** \brief Predict first pass after a certain time.
* \param sat Pointer to the satellite data.
* \param qth Pointer to the location data.
* \param start Starting time.
* \param maxdt The maximum number of days to look ahead (0 for no limit).
* \return Pointer to a newly allocated pass_t structure or NULL if
* there was an error.
*
* This function will find the first upcoming pass with AOS no earlier than
* t = start and no later than t = (start+maxdt).
*
* \note For no time limit use maxdt = 0.0
*
* \note the data in sat will be corrupt (future) and must be refreshed
* by the caller, if the caller will need it later on (eg. if the caller
* is GtkSatList).
*
* \note Prepending to a singly linked list is much faster than appending.
* Therefore, the elements are prepended whereafter the GSList is
* reversed
*/
pass_t *
get_pass (sat_t *sat, qth_t *qth, gdouble start, gdouble maxdt)
{
gdouble aos = 0.0; /* time of AOS */
gdouble tca = 0.0; /* time of TCA */
gdouble los = 0.0; /* time of LOS */
gdouble dt = 0.0; /* time diff */
gdouble step = 0.0; /* time step */
gdouble t0 = start;
gdouble t; /* current time counter */
gdouble tres = 0.0; /* required time resolution */
gdouble max_el = 0.0; /* maximum elevation */
pass_t *pass = NULL;
pass_detail_t *detail = NULL;
gboolean done = FALSE;
guint iter = 0; /* number of iterations */
/* FIXME: watchdog */
/* get time resolution; sat-cfg stores it in seconds */
tres = sat_cfg_get_int (SAT_CFG_INT_PRED_RESOLUTION) / 86400.0;
/* loop until we find a pass with elevation > SAT_CFG_INT_PRED_MIN_EL
or we run out of time
FIXME: we should have a safety break
*/
while (!done) {
aos = find_aos (sat, qth, t0, maxdt);
/* aos = 0.0 means no aos */
if (aos == 0.0) {
done = TRUE;
}
/* check whether we are within time limits;
maxdt = 0 mean no time limit.
*/
else if ((maxdt > 0.0) && (aos > (start + maxdt)) ) {
done = TRUE;
}
else {
los = find_los (sat, qth, aos + 0.001, maxdt); // +1.5 min later
dt = los - aos;
/* get time step, which will give us the max number of entries */
step = dt / sat_cfg_get_int (SAT_CFG_INT_PRED_NUM_ENTRIES);
/* but if this is smaller than the required resolution
we go with the resolution
*/
if (step < tres)
step = tres;
/* create a pass_t entry; FIXME: g_try_new in 2.8 */
pass = g_new (pass_t, 1);
pass->aos = aos;
pass->los = los;
pass->max_el = 0.0;
pass->aos_az = 0.0;
pass->los_az = 0.0;
pass->maxel_az = 0.0;
pass->vis[0] = '-';
pass->vis[1] = '-';
pass->vis[2] = '-';
pass->vis[3] = 0;
pass->satname = g_strdup (sat->tle.sat_name);
pass->details = NULL;
/* iterate over each time step */
for (t = pass->aos; t <= pass->los; t += step) {
/* calculate satellite data */
predict_calc (sat, qth, t);
/* in the first iter we want to store
pass->aos_az
*/
if (t == pass->aos) {
pass->aos_az = sat->az;
pass->orbit = sat->orbit;
}
/* append details to sat->details */
detail = g_new (pass_detail_t, 1);
detail->time = t;
detail->pos.x = sat->pos.x;
detail->pos.y = sat->pos.y;
detail->pos.z = sat->pos.z;
detail->pos.w = sat->pos.w;
detail->vel.x = sat->vel.x;
detail->vel.y = sat->vel.y;
detail->vel.z = sat->vel.z;
detail->vel.w = sat->vel.w;
detail->velo = sat->velo;
detail->az = sat->az;
detail->el = sat->el;
detail->range = sat->range;
detail->range_rate = sat->range_rate;
detail->lat = sat->ssplat;
detail->lon = sat->ssplon;
detail->alt = sat->alt;
detail->ma = sat->ma;
detail->phase = sat->phase;
detail->footprint = sat->footprint;
detail->orbit = sat->orbit;
detail->vis = get_sat_vis (sat, qth, t);
/* also store visibility "bit" */
switch (detail->vis) {
case SAT_VIS_VISIBLE:
pass->vis[0] = 'V';
break;
case SAT_VIS_DAYLIGHT:
pass->vis[1] = 'D';
break;
case SAT_VIS_ECLIPSED:
pass->vis[2] = 'E';
break;
default:
break;
}
pass->details = g_slist_prepend (pass->details, detail);
/* store elevation if greater than the
previously stored one
*/
if (sat->el > max_el) {
max_el = sat->el;
tca = t;
pass->maxel_az = sat->az;
}
/* g_print ("TIME: %f\tAZ: %f\tEL: %f (MAX: %f)\n", */
/* t, sat->az, sat->el, max_el); */
}
pass->details = g_slist_reverse (pass->details);
/* store los_az, max_el and tca */
pass->los_az = sat->az;
pass->max_el = max_el;
pass->tca = tca;
/* check whether this pass is good */
if (max_el >= sat_cfg_get_int (SAT_CFG_INT_PRED_MIN_EL)) {
done = TRUE;
}
else {
done = FALSE;
t0 = los + 0.014; // +20 min
free_pass (pass);
pass = NULL;
}
iter++;
}
}
return pass;
}
/** \brief Predict passes after a certain time.
*
*
* This function calculates num upcoming passes with AOS no earlier
* than t = start and not later that t = (start+maxdt). The function will
* repeatedly call get_pass until
* the number of predicted passes is equal to num, the time has reached
* limit or the get_pass function returns NULL.
*
* \note For no time limit use maxdt = 0.0
*
* \note the data in sat will be corrupt (future) and must be refreshed
* by the caller, if the caller will need it later on (eg. if the caller
* is GtkSatList).
*
* \note Prepending to a singly linked list is much faster than appending.
* Therefore, the elements are prepended whereafter the GSList is
* reversed
*/
GSList *
get_passes (sat_t *sat, qth_t *qth, gdouble start, gdouble maxdt, guint num)
{
GSList *passes = NULL;
pass_t *pass = NULL;
guint i;
gdouble t;
/* if no number has been specified
set it to something big */
if (num == 0)
num = 100;
t = start;
for (i = 0; i < num; i++) {
pass = get_pass (sat, qth, t, maxdt);
if (pass != NULL) {
passes = g_slist_prepend (passes, pass);
t = pass->los + 0.014; // +20 min
/* if maxdt > 0.0 check whether we have reached t = start+maxdt
if yes finish predictions
*/
if ((maxdt > 0.0) && (t >= (start+maxdt))) {
i = num;
}
}
else {
/* we can't get any more passes */
i = num;
}
}
if (passes != NULL)
passes = g_slist_reverse (passes);
return passes;
}
pass_t *
copy_pass (pass_t *pass)
{
pass_t *new;
new = g_try_new (pass_t, 1);
if (new != NULL) {
new->aos = pass->aos;
new->los = pass->los;
new->max_el = pass->max_el;
new->aos_az = pass->aos_az;
new->los_az = pass->los_az;
new->orbit = pass->orbit;
new->maxel_az = pass->maxel_az;
new->vis[0] = pass->vis[0];
new->vis[1] = pass->vis[1];
new->vis[2] = pass->vis[2];
new->vis[3] = pass->vis[3];
new->details = copy_pass_details (pass->details);
if (pass->satname != NULL)
new->satname = g_strdup (pass->satname);
else
new->satname = NULL;
}
return new;
}
GSList *
copy_pass_details (GSList *details)
{
GSList *new = NULL;
guint i,n;
n = g_slist_length (details);
for (i = 0; i < n; i++) {
new = g_slist_prepend (new,
copy_pass_detail (PASS_DETAIL (g_slist_nth_data (details, i))));
}
new = g_slist_reverse (new);
return new;
}
pass_detail_t *
copy_pass_detail (pass_detail_t *detail)
{
pass_detail_t *new;
/* create a pass_t entry; FIXME: g_try_new in 2.8 */
new = g_new (pass_detail_t, 1);
new->time = detail->time;
new->pos.x = detail->pos.x;
new->pos.y = detail->pos.y;
new->pos.z = detail->pos.z;
new->pos.w = detail->pos.w;
new->vel.x = detail->vel.x;
new->vel.y = detail->vel.y;
new->vel.z = detail->vel.z;
new->vel.w = detail->vel.w;
new->velo = detail->velo;
new->az = detail->az;
new->el = detail->el;
new->range = detail->range;
new->range_rate = detail->range_rate;
new->lat = detail->lat;
new->lon = detail->lon;
new->alt = detail->alt;
new->ma = detail->ma;
new->phase = detail->phase;
new->footprint = detail->footprint;
new->orbit = detail->orbit;
new->vis = detail->vis;
return new;
}
/** \brief Free a pass_t structure. */
void
free_pass (pass_t *pass)
{
free_pass_details (pass->details);
if (pass->satname != NULL) {
g_free (pass->satname);
pass->satname = NULL;
}
g_free (pass);
pass = NULL;
}
/** \brief Free a list of passes. */
void
free_passes (GSList *passes)
{
guint n,i;
gpointer pass;
n = g_slist_length (passes);
for (i = 0; i < n; i++) {
pass = g_slist_nth_data (passes, i);
/* free element data */
free_pass (PASS (pass));
}
/* now free the list elements */
g_slist_free (passes);
passes = NULL;
}
/** \brief Free a pass detail structure.
*
* This function is not rarely useful except for the
* free_pass function.
*
*/
void
free_pass_detail (pass_detail_t *detail)
{
g_free (detail);
detail = NULL;
}
/** \brief Free the whole list of details.
*
*/
void
free_pass_details (GSList *details)
{
guint n,i;
gpointer detail;
n = g_slist_length (details);
for (i = 0; i < n; i++) {
detail = g_slist_nth_data (details, i);
/* free element data */
free_pass_detail (PASS_DETAIL (detail));
}
/* free list elements */
g_slist_free (details);
details = NULL;
}
/** \brief Predict first pass after a certain time disergarding any minimum El setting.
* \param sat Pointer to the satellite data.
* \param qth Pointer to the location data.
* \param start Starting time.
* \param maxdt The maximum number of days to look ahead (0 for no limit).
* \return Pointer to a newly allocated pass_t structure or NULL if
* there was an error.
*
* This function will find the first upcoming pass with AOS no earlier than
* t = start and no later than t = (start+maxdt). Since the intented use of this
* function is to get the details of the current pass of a satellite, this function
* does not care of the minimum elevation setting in sat-cfg.
*
* \note For no time limit use maxdt = 0.0
*
* \note the data in sat will be corrupt (future) and must be refreshed
* by the caller, if the caller will need it later on (eg. if the caller
* is GtkSatList).
*
* \note Prepending to a singly linked list is much faster than appending.
* Therefore, the elements are prepended whereafter the GSList is
* reversed
*/
pass_t *
get_pass_no_min_el (sat_t *sat, qth_t *qth, gdouble start, gdouble maxdt)
{
gdouble aos = 0.0; /* time of AOS */
gdouble tca = 0.0; /* time of TCA */
gdouble los = 0.0; /* time of LOS */
gdouble dt = 0.0; /* time diff */
gdouble step = 0.0; /* time step */
gdouble t0 = start;
gdouble t; /* current time counter */
gdouble tres = 0.0; /* required time resolution */
gdouble max_el = 0.0; /* maximum elevation */
pass_t *pass = NULL;
pass_detail_t *detail = NULL;
gboolean done = FALSE;
/* FIXME: watchdog */
/* get time resolution; sat-cfg stores it in seconds */
tres = sat_cfg_get_int (SAT_CFG_INT_PRED_RESOLUTION) / 86400.0;
aos = find_aos (sat, qth, t0, maxdt);
/* aos = 0.0 means no aos */
if (aos == 0.0) {
done = TRUE;
}
/* check whether we are within time limits;
maxdt = 0 mean no time limit.
*/
else if ((maxdt > 0.0) && (aos > (start + maxdt))) {
done = TRUE;
}
else {
los = find_los (sat, qth, aos + 0.001, maxdt); // +1.5 min later
dt = los - aos;
/* get time step, which will give us the max number of entries */
step = dt / sat_cfg_get_int (SAT_CFG_INT_PRED_NUM_ENTRIES);
/* but if this is smaller than the required resolution
we go with the resolution
*/
if (step < tres)
step = tres;
/* create a pass_t entry; FIXME: g_try_new in 2.8 */
pass = g_new (pass_t, 1);
pass->aos = aos;
pass->los = los;
pass->max_el = 0.0;
pass->aos_az = 0.0;
pass->los_az = 0.0;
pass->maxel_az = 0.0;
pass->vis[0] = '-';
pass->vis[1] = '-';
pass->vis[2] = '-';
pass->vis[3] = 0;
pass->satname = g_strdup (sat->tle.sat_name);
pass->details = NULL;
/* iterate over each time step */
for (t = pass->aos; t <= pass->los; t += step) {
/* calculate satellite data */
predict_calc (sat, qth, t);
/* in the first iter we want to store
pass->aos_az
*/
if (t == pass->aos) {
pass->aos_az = sat->az;
pass->orbit = sat->orbit;
}
/* append details to sat->details */
detail = g_new (pass_detail_t, 1);
detail->time = t;
detail->pos.x = sat->pos.x;
detail->pos.y = sat->pos.y;
detail->pos.z = sat->pos.z;
detail->pos.w = sat->pos.w;
detail->vel.x = sat->vel.x;
detail->vel.y = sat->vel.y;
detail->vel.z = sat->vel.z;
detail->vel.w = sat->vel.w;
detail->velo = sat->velo;
detail->az = sat->az;
detail->el = sat->el;
detail->range = sat->range;
detail->range_rate = sat->range_rate;
detail->lat = sat->ssplat;
detail->lon = sat->ssplon;
detail->alt = sat->alt;
detail->ma = sat->ma;
detail->phase = sat->phase;
detail->footprint = sat->footprint;
detail->orbit = sat->orbit;
detail->vis = get_sat_vis (sat, qth, t);
/* also store visibility "bit" */
switch (detail->vis) {
case SAT_VIS_VISIBLE:
pass->vis[0] = 'V';
break;
case SAT_VIS_DAYLIGHT:
pass->vis[1] = 'D';
break;
case SAT_VIS_ECLIPSED:
pass->vis[2] = 'E';
break;
default:
break;
}
pass->details = g_slist_prepend (pass->details, detail);
/* store elevation if greater than the
previously stored one
*/
if (sat->el > max_el) {
max_el = sat->el;
tca = t;
pass->maxel_az = sat->az;
}
/* g_print ("TIME: %f\tAZ: %f\tEL: %f (MAX: %f)\n", */
/* t, sat->az, sat->el, max_el); */
}
pass->details = g_slist_reverse (pass->details);
/* store los_az, max_el and tca */
pass->los_az = sat->az;
pass->max_el = max_el;
pass->tca = tca;
}
return pass;
}
/** \brief Get current pass.
* \param sat Pointer to the satellite data.
* \param qth Pointer to the QTH data.
* \param start Time to start calculations; use 0.0 for now.
* \return Pointer to a newly allocated pass_t structure or NULL if
* there was an error.
*
* Assuming that sat->el > 0.0 this function calculates the details of the
* current pass from AOS time to LOS time.
* First the function goes back in time to before the AOS, then it calls
* the get_pass_no_min_el function to get the details of the current pass
* disregarding any minimum elevation requirements.
*
* \note The start parameter has been introduced to allow correct use of this
* function in non-realtime cases.
*
*/
pass_t *
get_current_pass (sat_t *sat, qth_t *qth, gdouble start)
{
gdouble t;
if (start > 0.0)
t = start;
else
t = get_current_daynum ();
predict_calc (sat, qth, t);
/* find a time before AOS */
while (sat->el > -2.0) {
predict_calc (sat, qth, t);
t -= 0.007; // +10 min
}
return get_pass_no_min_el (sat, qth, t, 0.0);
}