Completed
Push — master ( d35909...f740b5 )
by Yannick
06:46
created

Predict_Sat::geostationary()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Ported to PHP from gpredict by Bill Shupp
5
 */
6
7
//require_once 'Predict.php';
8
require_once 'SGPSDP.php';
9
require_once 'Vector.php';
10
require_once 'SGSDPStatic.php';
11
require_once 'SGPObs.php';
12
require_once 'Solar.php';
13
require_once 'DeepArg.php';
14
require_once 'DeepStatic.php';
15
require_once 'Geodetic.php';
16
require_once 'ObsSet.php';
17
require_once 'Time.php';
18
require_once 'Math.php';
19
20
/**
21
 * Contains satellite data and related methods.
22
 */
23
class Predict_Sat
24
{
25
    // Fifth root of a hundred, used for magnitude calculation
26
    const POGSONS_RATIO = 2.5118864315096;
27
28
    public $name     = null;
29
    public $nickname = null;
30
    public $website  = null;
31
32
    public $tle      = null;   /*!< Keplerian elements */
33
    public $flags    = 0;      /*!< Flags for algo ctrl */
34
    public $sgps     = null;
35
    public $dps      = null;
36
    public $deep_arg = null;
37
    public $pos      = null;   /*!< Raw position and range */
38
    public $vel      = null;   /*!< Raw velocity */
39
40
    /*** FIXME: REMOVE */
41
    public $bearing = null;   /*!< Az, El, range and vel */
42
    public $astro   = null;   /*!< Ra and Decl */
43
    /*** END */
44
45
    /* time keeping fields */
46
    public $jul_epoch = null;
47
    public $jul_utc   = null;
48
    public $tsince    = null;
49
    public $aos       = null;    /*!< Next AOS. */
50
    public $los       = null;    /*!< Next LOS */
51
52
    public $az         = null;   /*!< Azimuth [deg] */
53
    public $el         = null;   /*!< Elevation [deg] */
54
    public $range      = null;   /*!< Range [km] */
55
    public $range_rate = null;   /*!< Range Rate [km/sec] */
56
    public $ra         = null;   /*!< Right Ascension [deg] */
57
    public $dec        = null;   /*!< Declination [deg] */
58
    public $ssplat     = null;   /*!< SSP latitude [deg] */
59
    public $ssplon     = null;   /*!< SSP longitude [deg] */
60
    public $alt        = null;   /*!< altitude [km] */
61
    public $velo       = null;   /*!< velocity [km/s] */
62
    public $ma         = null;   /*!< mean anomaly */
63
    public $footprint  = null;   /*!< footprint */
64
    public $phase      = null;   /*!< orbit phase */
65
    public $meanmo     = null;   /*!< mean motion kept in rev/day */
66
    public $orbit      = null;   /*!< orbit number */
67
    public $otype      = null;   /*!< orbit type. */
68
69
    public function __construct(Predict_TLE $tle)
70
    {
71
        $headerParts    = explode(' ', $tle->header);
72
        $this->name     = $headerParts[0];
73
        $this->nickname = $this->name;
74
        $this->tle      = $tle;
75
        $this->pos      = new Predict_Vector();
76
        $this->vel      = new Predict_Vector();
77
        $this->sgps     = new Predict_SGSDPStatic();
78
        $this->deep_arg = new Predict_DeepArg();
79
        $this->dps      = new Predict_DeepStatic();
80
81
        $this->select_ephemeris();
82
        $this->sat_data_init_sat($this);
83
    }
84
85
    /* Selects the apropriate ephemeris type to be used */
86
    /* for predictions according to the data in the TLE */
87
    /* It also processes values in the tle set so that  */
88
    /* they are apropriate for the sgp4/sdp4 routines   */
89
    public function select_ephemeris()
90
    {
91
        /* Preprocess tle set */
92
        $this->tle->xnodeo *= Predict::de2ra;
93
        $this->tle->omegao *= Predict::de2ra;
94
        $this->tle->xmo    *= Predict::de2ra;
95
        $this->tle->xincl  *= Predict::de2ra;
96
        $temp = Predict::twopi / Predict::xmnpda / Predict::xmnpda;
97
98
        /* store mean motion before conversion */
99
        $this->meanmo       = $this->tle->xno;
100
        $this->tle->xno     = $this->tle->xno * $temp * Predict::xmnpda;
101
        $this->tle->xndt2o *= $temp;
102
        $this->tle->xndd6o  = $this->tle->xndd6o * $temp / Predict::xmnpda;
103
        $this->tle->bstar  /= Predict::ae;
104
105
        /* Period > 225 minutes is deep space */
106
        $dd1 = Predict::xke / $this->tle->xno;
107
        $dd2 = Predict::tothrd;
108
        $a1 = pow($dd1, $dd2);
109
        $r1 = cos($this->tle->xincl);
110
        $dd1 = 1.0 - $this->tle->eo * $this->tle->eo;
111
        $temp = Predict::ck2 * 1.5 * ($r1 * $r1 * 3.0 - 1.0) / pow($dd1, 1.5);
112
        $del1 = $temp / ($a1 * $a1);
113
        $ao = $a1 * (1.0 - $del1 * (Predict::tothrd * 0.5 + $del1 *
114
                                 ($del1 * 1.654320987654321 + 1.0)));
115
        $delo = $temp / ($ao * $ao);
116
        $xnodp = $this->tle->xno / ($delo + 1.0);
117
118
        /* Select a deep-space/near-earth ephemeris */
119
        if (Predict::twopi / $xnodp / Predict::xmnpda >= .15625) {
120
            $this->flags |= Predict_SGPSDP::DEEP_SPACE_EPHEM_FLAG;
121
        } else {
122
            $this->flags &= ~Predict_SGPSDP::DEEP_SPACE_EPHEM_FLAG;
123
        }
124
    }
125
126
    /** Initialise satellite data.
127
     *  @param sat The satellite to initialise.
128
     *  @param qth Optional QTH info, use (0,0) if NULL.
129
     *
130
     * This function calculates the satellite data at t = 0, ie. epoch time
131
     * The function is called automatically by gtk_sat_data_read_sat.
132
     */
133
    public function sat_data_init_sat(Predict_Sat $sat, Predict_QTH $qth = null)
134
    {
135
        $obs_geodetic = new Predict_Geodetic();
136
        $obs_set = new Predict_ObsSet();
137
        $sat_geodetic = new Predict_Geodetic();
138
        /* double jul_utc, age; */
139
140
        $jul_utc = Predict_Time::Julian_Date_of_Epoch($sat->tle->epoch); // => tsince = 0.0
141
        $sat->jul_epoch = $jul_utc;
142
143
        /* initialise observer location */
144
        if ($qth != null) {
145
            $obs_geodetic->lon = $qth->lon * Predict::de2ra;
146
            $obs_geodetic->lat = $qth->lat * Predict::de2ra;
147
            $obs_geodetic->alt = $qth->alt / 1000.0;
148
            $obs_geodetic->theta = 0;
149
        }
150
        else {
151
            $obs_geodetic->lon = 0.0;
152
            $obs_geodetic->lat = 0.0;
153
            $obs_geodetic->alt = 0.0;
154
            $obs_geodetic->theta = 0;
155
        }
156
157
        /* execute computations */
158
        $sdpsgp = Predict_SGPSDP::getInstance($sat);
159
        if ($sat->flags & Predict_SGPSDP::DEEP_SPACE_EPHEM_FLAG) {
160
            $sdpsgp->SDP4($sat, 0.0);
161
        } else {
162
            $sdpsgp->SGP4($sat, 0.0);
163
        }
164
165
        /* scale position and velocity to km and km/sec */
166
        Predict_Math::Convert_Sat_State($sat->pos, $sat->vel);
167
168
        /* get the velocity of the satellite */
169
        $sat->vel->w = sqrt($sat->vel->x * $sat->vel->x + $sat->vel->y * $sat->vel->y + $sat->vel->z * $sat->vel->z);
0 ignored issues
show
Documentation Bug introduced by
The property $w was declared of type integer, but sqrt($sat->vel->x * $sat...>vel->z * $sat->vel->z) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
170
        $sat->velo = $sat->vel->w;
171
        Predict_SGPObs::Calculate_Obs($jul_utc, $sat->pos, $sat->vel, $obs_geodetic, $obs_set);
172
        Predict_SGPObs::Calculate_LatLonAlt($jul_utc, $sat->pos, $sat_geodetic);
173
174
        while ($sat_geodetic->lon < -Predict::pi) {
175
            $sat_geodetic->lon += Predict::twopi;
176
        }
177
178
        while ($sat_geodetic->lon > Predict::pi) {
179
            $sat_geodetic->lon -= Predict::twopi;
180
        }
181
182
        $sat->az = Predict_Math::Degrees($obs_set->az);
183
        $sat->el = Predict_Math::Degrees($obs_set->el);
184
        $sat->range = $obs_set->range;
185
        $sat->range_rate = $obs_set->range_rate;
186
        $sat->ssplat = Predict_Math::Degrees($sat_geodetic->lat);
187
        $sat->ssplon = Predict_Math::Degrees($sat_geodetic->lon);
188
        $sat->alt = $sat_geodetic->alt;
189
        $sat->ma = Predict_Math::Degrees($sat->phase);
190
        $sat->ma *= 256.0 / 360.0;
191
        $sat->footprint = 2.0 * Predict::xkmper * acos (Predict::xkmper/$sat->pos->w);
192
        $age = 0.0;
193
        $sat->orbit = floor(($sat->tle->xno * Predict::xmnpda / Predict::twopi +
194
                                   $age * $sat->tle->bstar * Predict::ae) * $age +
195
                                  $sat->tle->xmo / Predict::twopi) + $sat->tle->revnum - 1;
196
197
        /* orbit type */
198
        $sat->otype = $sat->get_orbit_type($sat);
199
    }
200
201
    public function get_orbit_type(Predict_Sat $sat)
202
    {
203
         $orbit = Predict_SGPSDP::ORBIT_TYPE_UNKNOWN;
0 ignored issues
show
Unused Code introduced by
$orbit is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
204
205
         if ($this->geostationary($sat)) {
206
              $orbit = Predict_SGPSDP::ORBIT_TYPE_GEO;
207
         } else if ($this->decayed($sat)) {
208
              $orbit = Predict_SGPSDP::ORBIT_TYPE_DECAYED;
209
         } else {
210
              $orbit = Predict_SGPSDP::ORBIT_TYPE_UNKNOWN;
211
         }
212
213
         return $orbit;
214
    }
215
216
217
    /** Determinte whether satellite is in geostationary orbit.
218
     *  @author John A. Magliacane, KD2BD
219
     *  @param sat Pointer to satellite data.
220
     *  @return TRUE if the satellite appears to be in geostationary orbit,
221
     *          FALSE otherwise.
222
     *
223
     * A satellite is in geostationary orbit if
224
     *
225
     *     fabs (sat.meanmotion - 1.0027) < 0.0002
226
     *
227
     * Note: Appearantly, the mean motion can deviate much more from 1.0027 than 0.0002
228
     */
229
    public function geostationary(Predict_Sat $sat)
230
    {
231
         if (abs($sat->meanmo - 1.0027) < 0.0002) {
232
              return true;
233
         } else {
234
              return false;
235
        }
236
    }
237
238
239
    /** Determine whether satellite has decayed.
240
     *  @author John A. Magliacane, KD2BD
241
     *  @author Alexandru Csete, OZ9AEC
242
     *  @param sat Pointer to satellite data.
243
     *  @return TRUE if the satellite appears to have decayed, FALSE otherwise.
244
     *  @bug Modified version of the predict code but it is not tested.
245
     *
246
     * A satellite is decayed if
247
     *
248
     *    satepoch + ((16.666666 - sat.meanmo) / (10.0*fabs(sat.drag))) < "now"
249
     *
250
     */
251
    public function decayed(Predict_Sat $sat)
252
    {
253
        /* tle.xndt2o/(twopi/xmnpda/xmnpda) is the value before converted the
254
           value matches up with the value in predict 2.2.3 */
255
        /*** FIXME decayed is treated as a static quantity.
256
             It is time dependent. Also sat->jul_utc is often zero
257
             when this function is called
258
        ***/
259
        if ((10.0 * abs($sat->tle->xndt2o / (Predict::twopi / Predict::xmnpda / Predict::xmnpda))) == 0) {
260
    		return true;
261
    	} elseif ($sat->jul_epoch + ((16.666666 - $sat->meanmo) /
262
                               (10.0 * abs($sat->tle->xndt2o / (Predict::twopi / Predict::xmnpda / Predict::xmnpda)))) < $sat->jul_utc) {
263
              return true;
264
        } else {
265
              return false;
266
        }
267
    }
268
269
    /**
270
     * Experimental attempt at calculating apparent magnitude.  Known intrinsic
271
     * magnitudes are listed inside the function for now.
272
     *
273
     * @param float       $time The daynum the satellite is calculated for
274
     * @param Predict_QTH $qth  The observer location
275
     *
276
     * @return null on failure, float otherwise
277
     */
278
    public function calculateApparentMagnitude($time, Predict_QTH $qth)
279
    {
280
        // Recorded intrinsic magnitudes and their respective
281
        // illumination and distance from heavens-above.com
282
        static $intrinsicMagnitudes = array(
283
            '25544' => array(
284
                'mag'      => -1.3,
285
                'illum'    => .5,
286
                'distance' => 1000,
287
            )
288
        );
289
290
        // Return null if we don't have a record of the intrinsic mag
291
        if (!isset($intrinsicMagnitudes[$this->tle->catnr])) {
292
            return null;
293
        }
294
        $imag = $intrinsicMagnitudes[$this->tle->catnr];
295
296
        // Convert the observer's geodetic info to radians and km so
297
        // we can compare vectors
298
        $observerGeo      = new Predict_Geodetic();
299
        $observerGeo->lat = Predict_Math::Radians($qth->lat);
300
        $observerGeo->lon = Predict_Math::Radians($qth->lon);
301
        $observerGeo->alt = $qth->alt * 1000;
302
303
        // Now determine the sun and observer positions
304
        $observerPos      = new Predict_Vector();
305
        $observerVel      = new Predict_Vector();
306
        $solarVector      = new Predict_Vector();
307
        Predict_Solar::Calculate_Solar_Position($time, $solarVector);
308
        Predict_SGPObs::Calculate_User_PosVel($time, $observerGeo, $observerPos, $observerVel);
309
310
        // Determine the solar phase and and thus the percent illumination
311
        $observerSatPos = new Predict_Vector();
312
        Predict_Math::Vec_Sub($this->pos, $observerPos, $observerSatPos);
313
        $phaseAngle = Predict_Math::Degrees(Predict_Math::Angle($solarVector, $observerSatPos));
314
        $illum      = $phaseAngle / 180;
315
316
        $illuminationChange            = $illum / $imag['illum'];
317
        $inverseSquareOfDistanceChange = pow(($imag['distance'] / $this->range), 2);
318
        $changeInMagnitude             = log(
319
            $illuminationChange * $inverseSquareOfDistanceChange,
320
            self::POGSONS_RATIO
321
        );
322
323
        return $imag['mag'] - $changeInMagnitude;
324
    }
325
}
326