tle.c
Go to the documentation of this file.
1 /*
2  * The RTKLIB software package is distributed under the following BSD 2-clause
3  * license (http://opensource.org/licenses/BSD-2-Clause) and additional two
4  * exclusive clauses. Users are permitted to develop, produce or sell their own
5  * non-commercial or commercial products utilizing, linking or including RTKLIB as
6  * long as they comply with the license.
7  *
8  * Copyright (c) 2007-2013, T. Takasu, All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice, this
14  * list of conditions and the following disclaimer.
15  *
16  * - Redistributions in binary form must reproduce the above copyright notice, this
17  * list of conditions and the following disclaimer in the documentation and/or
18  * other materials provided with the distribution.
19  *
20  * - The software package includes some companion executive binaries or shared
21  * libraries necessary to execute APs on Windows. These licenses succeed to the
22  * original ones of these software.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
28  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
30  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
33  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 // This file is an excerpt from rtklib.
37 
38 /*------------------------------------------------------------------------------
39 * tle.c: NORAD TLE (two line element) functions
40 *
41 * Copyright (C) 2012-2013 by T.TAKASU, All rights reserved.
42 *
43 * references:
44 * [1] F.R.Hoots and R.L.Roehrich, Spacetrack report No.3, Models for
45 * propagation of NORAD element sets, December 1980
46 * [2] D.A.Vallado, P.Crawford, R.Hujsak and T.S.Kelso, Revisiting
47 * Spacetrack Report #3, AIAA 2006-6753, 2006
48 * [3] CelesTrak (http://www.celestrak.com)
49 *
50 * version : $Revision:$ $Date:$
51 * history : 2012/11/01 1.0 new
52 * 2013/01/25 1.1 fix bug on binary search
53 * 2014/08/26 1.2 fix bug on tle_pos() to get tle by satid or desig
54 *-----------------------------------------------------------------------------*/
55 
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <math.h>
60 #include <time.h>
61 
62 #include "tle.h"
63 
64 #define OMGE 7.2921151467E-5 /* earth angular velocity (IS-GPS) (rad/s) */
65 #define PI 3.1415926535897932 /* pi */
66 
67 #define MINPRNGPS 1 /* min satellite PRN number of GPS */
68 #define MAXPRNGPS 32 /* max satellite PRN number of GPS */
69 #define NSATGPS (MAXPRNGPS-MINPRNGPS+1) /* number of GPS satellites */
70 #define MINPRNGLO 1 /* min satellite slot number of GLONASS */
71 #define MAXPRNGLO 25 /* max satellite slot number of GLONASS */
72 #define NSATGLO (MAXPRNGLO-MINPRNGLO+1) /* number of GLONASS satellites */
73 #define MINPRNGAL 1 /* min satellite PRN number of Galileo */
74 #define MAXPRNGAL 36 /* max satellite PRN number of Galileo */
75 #define NSATGAL (MAXPRNGAL-MINPRNGAL+1) /* number of Galileo satellites */
76 #define MINPRNQZS 193 /* min satellite PRN number of QZSS */
77 #define MAXPRNQZS 199 /* max satellite PRN number of QZSS */
78 #define NSATQZS (MAXPRNQZS-MINPRNQZS+1) /* number of QZSS satellites */
79 #define MINPRNCMP 1 /* min satellite sat number of BeiDou */
80 #define MAXPRNCMP 62 /* max satellite sat number of BeiDou */
81 #define NSATCMP (MAXPRNCMP-MINPRNCMP+1) /* number of BeiDou satellites */
82 #define MINPRNLEO 1 /* min satellite sat number of LEO */
83 #define MAXPRNLEO 10 /* max satellite sat number of LEO */
84 #define NSATLEO (MAXPRNLEO-MINPRNLEO+1) /* number of LEO satellites */
85 #define MINPRNSBS 120 /* min satellite PRN number of SBAS */
86 #define MAXPRNSBS 142 /* max satellite PRN number of SBAS */
87 #define NSATSBS (MAXPRNSBS-MINPRNSBS+1) /* number of SBAS satellites */
88 #define MAXSAT (NSATGPS+NSATGLO+NSATGAL+NSATQZS+NSATCMP+NSATSBS+NSATLEO)
89 
90 #define MAXLEAPS 64 /* max number of leap seconds table */
91 static double leaps[MAXLEAPS+1][7]={ /* leap seconds (y,m,d,h,m,s,utc-gpst) */
92  {2017,1,1,0,0,0,-18},
93  {2015,7,1,0,0,0,-17},
94  {2012,7,1,0,0,0,-16},
95  {2009,1,1,0,0,0,-15},
96  {2006,1,1,0,0,0,-14},
97  {1999,1,1,0,0,0,-13},
98  {1997,7,1,0,0,0,-12},
99  {1996,1,1,0,0,0,-11},
100  {1994,7,1,0,0,0,-10},
101  {1993,7,1,0,0,0, -9},
102  {1992,7,1,0,0,0, -8},
103  {1991,1,1,0,0,0, -7},
104  {1990,1,1,0,0,0, -6},
105  {1988,1,1,0,0,0, -5},
106  {1985,7,1,0,0,0, -4},
107  {1983,7,1,0,0,0, -3},
108  {1982,7,1,0,0,0, -2},
109  {1981,7,1,0,0,0, -1},
110  {0}
111 };
112 
113 void trace(int level, const char *format, ...)
114 {
115 }
116 
117 /* add time --------------------------------------------------------------------
118 * add time to gtime_t struct
119 * args : gtime_t t I gtime_t struct
120 * double sec I time to add (s)
121 * return : gtime_t struct (t+sec)
122 *-----------------------------------------------------------------------------*/
123 gtime_t timeadd(gtime_t t, double sec)
124 {
125  double tt;
126 
127  t.sec+=sec; tt=floor(t.sec); t.time+=(int)tt; t.sec-=tt;
128  return t;
129 }
130 /* time difference -------------------------------------------------------------
131 * difference between gtime_t structs
132 * args : gtime_t t1,t2 I gtime_t structs
133 * return : time difference (t1-t2) (s)
134 *-----------------------------------------------------------------------------*/
135 double timediff(gtime_t t1, gtime_t t2)
136 {
137  return difftime(t1.time,t2.time)+t1.sec-t2.sec;
138 }
139 /* convert calendar day/time to time -------------------------------------------
140 * convert calendar day/time to gtime_t struct
141 * args : double *ep I day/time {year,month,day,hour,min,sec}
142 * return : gtime_t struct
143 * notes : proper in 1970-2037 or 1970-2099 (64bit time_t)
144 *-----------------------------------------------------------------------------*/
145 gtime_t epoch2time(const double *ep)
146 {
147  const int doy[]={1,32,60,91,121,152,182,213,244,274,305,335};
148  gtime_t time={0};
149  int days,sec,year=(int)ep[0],mon=(int)ep[1],day=(int)ep[2];
150 
151  if (year<1970||2099<year||mon<1||12<mon) return time;
152 
153  /* leap year if year%4==0 in 1901-2099 */
154  days=(year-1970)*365+(year-1969)/4+doy[mon-1]+day-2+(year%4==0&&mon>=3?1:0);
155  sec=(int)floor(ep[5]);
156  time.time=(time_t)days*86400+(int)ep[3]*3600+(int)ep[4]*60+sec;
157  time.sec=ep[5]-sec;
158  return time;
159 }
160 
161 /* gpstime to utc --------------------------------------------------------------
162 * convert gpstime to utc considering leap seconds
163 * args : gtime_t t I time expressed in gpstime
164 * return : time expressed in utc
165 * notes : ignore slight time offset under 100 ns
166 *-----------------------------------------------------------------------------*/
168 {
169  gtime_t tu;
170  int i;
171 
172  for (i=0;leaps[i][0]>0;i++) {
173  tu=timeadd(t,leaps[i][6]);
174  if (timediff(tu,epoch2time(leaps[i]))>=0.0) return tu;
175  }
176  return t;
177 }
178 
180 {
181  int i;
182 
183  for (i=0;leaps[i][0]>0;i++) {
184  if (timediff(t,epoch2time(leaps[i]))>=0.0) return timeadd(t,-leaps[i][6]);
185  }
186  return t;
187 }
188 
189 /* get earth rotation parameter values -----------------------------------------
190 * get earth rotation parameter values
191 * args : erp_t *erp I earth rotation parameters
192 * gtime_t time I time (gpst)
193 * double *erpv O erp values {xp,yp,ut1_utc,lod} (rad,rad,s,s/d)
194 * return : status (1:ok,0:error)
195 *-----------------------------------------------------------------------------*/
196 int geterp(const erp_t *erp, gtime_t time, double *erpv)
197 {
198  const double ep[]={2000,1,1,12,0,0};
199  double mjd,day,a;
200  int i,j,k;
201 
202  trace(4,"geterp:\n");
203 
204  if (erp->n<=0) return 0;
205 
206  mjd=51544.5+(timediff(gpst2utc(time),epoch2time(ep)))/86400.0;
207 
208  if (mjd<=erp->data[0].mjd) {
209  day=mjd-erp->data[0].mjd;
210  erpv[0]=erp->data[0].xp +erp->data[0].xpr*day;
211  erpv[1]=erp->data[0].yp +erp->data[0].ypr*day;
212  erpv[2]=erp->data[0].ut1_utc-erp->data[0].lod*day;
213  erpv[3]=erp->data[0].lod;
214  return 1;
215  }
216  if (mjd>=erp->data[erp->n-1].mjd) {
217  day=mjd-erp->data[erp->n-1].mjd;
218  erpv[0]=erp->data[erp->n-1].xp +erp->data[erp->n-1].xpr*day;
219  erpv[1]=erp->data[erp->n-1].yp +erp->data[erp->n-1].ypr*day;
220  erpv[2]=erp->data[erp->n-1].ut1_utc-erp->data[erp->n-1].lod*day;
221  erpv[3]=erp->data[erp->n-1].lod;
222  return 1;
223  }
224  for (j=0,k=erp->n-1;j<k-1;) {
225  i=(j+k)/2;
226  if (mjd<erp->data[i].mjd) k=i; else j=i;
227  }
228  if (erp->data[j].mjd==erp->data[j+1].mjd) {
229  a=0.5;
230  }
231  else {
232  a=(mjd-erp->data[j].mjd)/(erp->data[j+1].mjd-erp->data[j].mjd);
233  }
234  erpv[0]=(1.0-a)*erp->data[j].xp +a*erp->data[j+1].xp;
235  erpv[1]=(1.0-a)*erp->data[j].yp +a*erp->data[j+1].yp;
236  erpv[2]=(1.0-a)*erp->data[j].ut1_utc+a*erp->data[j+1].ut1_utc;
237  erpv[3]=(1.0-a)*erp->data[j].lod +a*erp->data[j+1].lod;
238  return 1;
239 }
240 
241 /* time to calendar day/time ---------------------------------------------------
242 * convert gtime_t struct to calendar day/time
243 * args : gtime_t t I gtime_t struct
244 * double *ep O day/time {year,month,day,hour,min,sec}
245 * return : none
246 * notes : proper in 1970-2037 or 1970-2099 (64bit time_t)
247 *-----------------------------------------------------------------------------*/
248 void time2epoch(gtime_t t, double *ep)
249 {
250  const int mday[]={ /* # of days in a month */
251  31,28,31,30,31,30,31,31,30,31,30,31,31,28,31,30,31,30,31,31,30,31,30,31,
252  31,29,31,30,31,30,31,31,30,31,30,31,31,28,31,30,31,30,31,31,30,31,30,31
253  };
254  int days,sec,mon,day;
255 
256  /* leap year if year%4==0 in 1901-2099 */
257  days=(int)(t.time/86400);
258  sec=(int)(t.time-(time_t)days*86400);
259  for (day=days%1461,mon=0;mon<48;mon++) {
260  if (day>=mday[mon]) day-=mday[mon]; else break;
261  }
262  ep[0]=1970+days/1461*4+mon/12; ep[1]=mon%12+1; ep[2]=day+1;
263  ep[3]=sec/3600; ep[4]=sec%3600/60; ep[5]=sec%60+t.sec;
264 }
265 
266 /* time to day and sec -------------------------------------------------------*/
267 static double time2sec(gtime_t time, gtime_t *day)
268 {
269  double ep[6],sec;
270  time2epoch(time,ep);
271  sec=ep[3]*3600.0+ep[4]*60.0+ep[5];
272  ep[3]=ep[4]=ep[5]=0.0;
273  *day=epoch2time(ep);
274  return sec;
275 }
276 
277 /* utc to gmst -----------------------------------------------------------------
278 * convert utc to gmst (Greenwich mean sidereal time)
279 * args : gtime_t t I time expressed in utc
280 * double ut1_utc I UT1-UTC (s)
281 * return : gmst (rad)
282 *-----------------------------------------------------------------------------*/
283 double utc2gmst(gtime_t t, double ut1_utc)
284 {
285  const double ep2000[]={2000,1,1,12,0,0};
286  gtime_t tut,tut0;
287  double ut,t1,t2,t3,gmst0,gmst;
288 
289  tut=timeadd(t,ut1_utc);
290  ut=time2sec(tut,&tut0);
291  t1=timediff(tut0,epoch2time(ep2000))/86400.0/36525.0;
292  t2=t1*t1; t3=t2*t1;
293  gmst0=24110.54841+8640184.812866*t1+0.093104*t2-6.2E-6*t3;
294  gmst=gmst0+1.002737909350795*ut;
295 
296  return fmod(gmst,86400.0)*PI/43200.0; /* 0 <= gmst <= 2*PI */
297 }
298 
299 /* multiply matrix -----------------------------------------------------------*/
300 void matmul(const char *tr, int n, int k, int m, double alpha,
301  const double *A, const double *B, double beta, double *C)
302 {
303  double d;
304  int i,j,x,f=tr[0]=='N'?(tr[1]=='N'?1:2):(tr[1]=='N'?3:4);
305 
306  for (i=0;i<n;i++) for (j=0;j<k;j++) {
307  d=0.0;
308  switch (f) {
309  case 1: for (x=0;x<m;x++) d+=A[i+x*n]*B[x+j*m]; break;
310  case 2: for (x=0;x<m;x++) d+=A[i+x*n]*B[j+x*k]; break;
311  case 3: for (x=0;x<m;x++) d+=A[x+i*m]*B[x+j*m]; break;
312  case 4: for (x=0;x<m;x++) d+=A[x+i*m]*B[j+x*k]; break;
313  }
314  if (beta==0.0) C[i+j*n]=alpha*d; else C[i+j*n]=alpha*d+beta*C[i+j*n];
315  }
316 }
317 
318 /* string to number ------------------------------------------------------------
319 * convert substring in string to number
320 * args : char *s I string ("... nnn.nnn ...")
321 * int i,n I substring position and width
322 * return : converted number (0.0:error)
323 *-----------------------------------------------------------------------------*/
324 double str2num(const char *s, int i, int n)
325 {
326  double value;
327  char str[256],*p=str;
328 
329  if (i<0||(int)strlen(s)<i||(int)sizeof(str)-1<n) return 0.0;
330  for (s+=i;*s&&--n>=0;s++) *p++=*s=='d'||*s=='D'?'E':*s; *p='\0';
331  return sscanf(str,"%lf",&value)==1?value:0.0;
332 }
333 
334 /* SGP4 model propagator by STR#3 (ref [1] sec.6,11) -------------------------*/
335 
336 #define DE2RA 0.174532925E-1
337 #define E6A 1.E-6
338 #define TOTHRD 0.66666667
339 #define TWOPI 6.2831853
340 #define XJ3 -0.253881E-5
341 #define XKE 0.743669161E-1
342 #define XKMPER 6378.135
343 #define XMNPDA 1440.0
344 #define AE 1.0
345 #define CK2 5.413080E-4 /* = 0.5*XJ2*AE*AE */
346 #define CK4 0.62098875E-6 /* = -0.375*XJ4*AE*AE*AE*AE */
347 #define QOMS2T 1.88027916E-9 /* = pow((QO-SO)*AE/XKMPER,4.0) */
348 #define S 1.01222928 /* = AE*(1.0+SO/XKMPER) */
349 
350 static void SGP4_STR3(double tsince, const tled_t *data, double *rs)
351 {
352  double xnodeo,omegao,xmo,eo,xincl,xno,xndt2o,xndd6o,bstar;
353  double a1,cosio,theta2,x3thm1,eosq,betao2,betao,del1,ao,delo,xnodp,aodp,s4;
354  double qoms24,perige,pinvsq,tsi,eta,etasq,eeta,psisq,coef,coef1,c1,c2,c3,c4;
355  double c5,sinio,a3ovk2,x1mth2,theta4,xmdot,x1m5th,omgdot,xhdot1,xnodot;
356  double omgcof,xmcof,xnodcf,t2cof,xlcof,aycof,delmo,sinmo,x7thm1,c1sq,d2,d3;
357  double d4,t3cof,t4cof,t5cof,xmdf,omgadf,xnoddf,omega,xmp,tsq,xnode,delomg;
358  double delm,tcube,tfour,a,e,xl,beta,xn,axn,xll,aynl,xlt,ayn,capu,sinepw;
359  double cosepw,epw,ecose,esine,elsq,pl,r,rdot,rfdot,betal,cosu,sinu,u,sin2u;
360  double cos2u,rk,uk,xnodek,xinck,rdotk,rfdotk,sinuk,cosuk,sinik,cosik,sinnok;
361  double cosnok,xmx,xmy,ux,uy,uz,vx,vy,vz,x,y,z,xdot,ydot,zdot;
362  double temp,temp1,temp2,temp3,temp4,temp5,temp6,tempa,tempe,templ;
363  int i,isimp;
364 
365  xnodeo=data->OMG*DE2RA;
366  omegao=data->omg*DE2RA;
367  xmo=data->M*DE2RA;
368  xincl=data->inc*DE2RA;
370  xno=data->n*temp*XMNPDA;
371  xndt2o=data->ndot*temp;
372  xndd6o=data->nddot*temp/XMNPDA;
373  bstar=data->bstar/AE;
374  eo=data->ecc;
375  /*
376  * recover original mean motion (xnodp) and semimajor axis (aodp)
377  * from input elements
378  */
379  a1=pow(XKE/xno,TOTHRD);
380  cosio=cos(xincl);
381  theta2=cosio*cosio;
382  x3thm1=3.0*theta2-1.0;
383  eosq=eo*eo;
384  betao2=1.0-eosq;
385  betao=sqrt(betao2);
386  del1=1.5*CK2*x3thm1/(a1*a1*betao*betao2);
387  ao=a1*(1.0-del1*(0.5*TOTHRD+del1*(1.0+134.0/81.0*del1)));
388  delo=1.5*CK2*x3thm1/(ao*ao*betao*betao2);
389  xnodp=xno/(1.0+delo);
390  aodp=ao/(1.0-delo);
391  /*
392  * initialization
393  * for perigee less than 220 kilometers, the isimp flag is set and
394  * the equations are truncated to linear variation in sqrt a and
395  * quadratic variation in mean anomaly. also, the c3 term, the
396  * delta omega term, and the delta m term are dropped.
397  */
398  isimp=0;
399  if ((aodp*(1.0-eo)/AE)<(220.0/XKMPER+AE)) isimp=1;
400 
401  /* for perigee below 156 km, the values of s and qoms2t are altered */
402  s4=S;
403  qoms24=QOMS2T;
404  perige=(aodp*(1.0-eo)-AE)*XKMPER;
405  if (perige<156.0) {
406  s4=perige-78.0;
407  if (perige<=98.0) s4=20.0;
408  qoms24=pow((120.0-s4)*AE/XKMPER,4.0);
409  s4=s4/XKMPER+AE;
410  }
411  pinvsq=1.0/(aodp*aodp*betao2*betao2);
412  tsi=1.0/(aodp-s4);
413  eta=aodp*eo*tsi;
414  etasq=eta*eta;
415  eeta=eo*eta;
416  psisq=fabs(1.0-etasq);
417  coef=qoms24*pow(tsi,4.0);
418  coef1=coef/pow(psisq,3.5);
419  c2=coef1*xnodp*(aodp*(1.0+1.5*etasq+eeta*(4.0+etasq))+0.75*
420  CK2*tsi/psisq*x3thm1*(8.0+3.0*etasq*(8.0+etasq)));
421  c1=bstar*c2;
422  sinio=sin(xincl);
423  a3ovk2=-XJ3/CK2*pow(AE,3.0);
424  c3=coef*tsi*a3ovk2*xnodp*AE*sinio/eo;
425  x1mth2=1.0-theta2;
426  c4=2.0*xnodp*coef1*aodp*betao2*(eta*
427  (2.0+0.5*etasq)+eo*(0.5+2.0*etasq)-2.0*CK2*tsi/
428  (aodp*psisq)*(-3.0*x3thm1*(1.0-2.0*eeta+etasq*
429  (1.5-0.5*eeta))+0.75*x1mth2*(2.0*etasq-eeta*
430  (1.0+etasq))*cos(2.0*omegao)));
431  c5=2.0*coef1*aodp*betao2*(1.0+2.75*(etasq+eeta)+eeta*etasq);
432  theta4=theta2*theta2;
433  temp1=3.0*CK2*pinvsq*xnodp;
434  temp2=temp1*CK2*pinvsq;
435  temp3=1.25*CK4*pinvsq*pinvsq*xnodp;
436  xmdot=xnodp+0.5*temp1*betao*x3thm1+0.0625*temp2*betao*
437  (13.0-78.0*theta2+137.0*theta4);
438  x1m5th=1.0-5.0*theta2;
439  omgdot=-0.5*temp1*x1m5th+0.0625*temp2*(7.0-114.0*theta2+
440  395.0*theta4)+temp3*(3.0-36.0*theta2+49.0*theta4);
441  xhdot1=-temp1*cosio;
442  xnodot=xhdot1+(0.5*temp2*(4.0-19.0*theta2)+2.0*temp3*(3.0-
443  7.0*theta2))*cosio;
444  omgcof=bstar*c3*cos(omegao);
445  xmcof=-TOTHRD*coef*bstar*AE/eeta;
446  xnodcf=3.5*betao2*xhdot1*c1;
447  t2cof=1.5*c1;
448  xlcof=0.125*a3ovk2*sinio*(3.0+5.0*cosio)/(1.0+cosio);
449  aycof=0.25*a3ovk2*sinio;
450  delmo=pow(1.0+eta*cos(xmo),3.0);
451  sinmo=sin(xmo);
452  x7thm1=7.0*theta2-1.0;
453 
454  if (isimp!=1) {
455  c1sq=c1*c1;
456  d2=4.0*aodp*tsi*c1sq;
457  temp=d2*tsi*c1/3.0;
458  d3=(17.0*aodp+s4)*temp;
459  d4=0.5*temp*aodp*tsi*(221.0*aodp+31.0*s4)*c1;
460  t3cof=d2+2.0*c1sq;
461  t4cof=0.25*(3.0*d3+c1*(12.0*d2+10.0*c1sq));
462  t5cof=0.2*(3.0*d4+12.0*c1*d3+6.0*d2*d2+15.0*c1sq*(2.0*d2+c1sq));
463  }
464  else {
465  d2=d3=d4=t3cof=t4cof=t5cof=0.0;
466  }
467  /* update for secular gravity and atmospheric drag */
468  xmdf=xmo+xmdot*tsince;
469  omgadf=omegao+omgdot*tsince;
470  xnoddf=xnodeo+xnodot*tsince;
471  omega=omgadf;
472  xmp=xmdf;
473  tsq=tsince*tsince;
474  xnode=xnoddf+xnodcf*tsq;
475  tempa=1.0-c1*tsince;
476  tempe=bstar*c4*tsince;
477  templ=t2cof*tsq;
478  if (isimp==1) {
479  delomg=omgcof*tsince;
480  delm=xmcof*(pow(1.0+eta*cos(xmdf),3.0)-delmo);
481  temp=delomg+delm;
482  xmp=xmdf+temp;
483  omega=omgadf-temp;
484  tcube=tsq*tsince;
485  tfour=tsince*tcube;
486  tempa=tempa-d2*tsq-d3*tcube-d4*tfour;
487  tempe=tempe+bstar*c5*(sin(xmp)-sinmo);
488  templ=templ+t3cof*tcube+tfour*(t4cof+tsince*t5cof);
489  }
490  a=aodp*pow(tempa,2.0);
491  e=eo-tempe;
492  xl=xmp+omega+xnode+xnodp*templ;
493  beta=sqrt(1.0-e*e);
494  xn=XKE/pow(a,1.5);
495 
496  /* long period periodics */
497  axn=e*cos(omega);
498  temp=1.0/(a*beta*beta);
499  xll=temp*xlcof*axn;
500  aynl=temp*aycof;
501  xlt=xl+xll;
502  ayn=e*sin(omega)+aynl;
503 
504  /* solve keplers equation */
505  capu=fmod(xlt-xnode,TWOPI);
506  temp2=capu;
507  for (i=0;i<10;i++) {
508  sinepw=sin(temp2);
509  cosepw=cos(temp2);
510  temp3=axn*sinepw;
511  temp4=ayn*cosepw;
512  temp5=axn*cosepw;
513  temp6=ayn*sinepw;
514  epw=(capu-temp4+temp3-temp2)/(1.0-temp5-temp6)+temp2;
515  if (fabs(epw-temp2)<=E6A) break;
516  temp2=epw;
517  }
518  /* short period preliminary quantities */
519  ecose=temp5+temp6;
520  esine=temp3-temp4;
521  elsq=axn*axn+ayn*ayn;
522  temp=1.0-elsq;
523  pl=a*temp;
524  r=a*(1.0-ecose);
525  temp1=1.0/r;
526  rdot=XKE*sqrt(a)*esine*temp1;
527  rfdot=XKE*sqrt(pl)*temp1;
528  temp2=a*temp1;
529  betal=sqrt(temp);
530  temp3=1.0/(1.0+betal);
531  cosu=temp2*(cosepw-axn+ayn*esine*temp3);
532  sinu=temp2*(sinepw-ayn-axn*esine*temp3);
533  u=atan2(sinu,cosu);
534  sin2u=2.0*sinu*cosu;
535  cos2u=2.0*cosu*cosu-1.0;
536  temp=1.0/pl;
537  temp1=CK2*temp;
538  temp2=temp1*temp;
539 
540  /* update for short periodics */
541  rk=r*(1.0-1.5*temp2*betal*x3thm1)+0.5*temp1*x1mth2*cos2u;
542  uk=u-0.25*temp2*x7thm1*sin2u;
543  xnodek=xnode+1.5*temp2*cosio*sin2u;
544  xinck=xincl+1.5*temp2*cosio*sinio*cos2u;
545  rdotk=rdot-xn*temp1*x1mth2*sin2u;
546  rfdotk=rfdot+xn*temp1*(x1mth2*cos2u+1.5*x3thm1);
547 
548  /* orientation vectors */
549  sinuk=sin(uk);
550  cosuk=cos(uk);
551  sinik=sin(xinck);
552  cosik=cos(xinck);
553  sinnok=sin(xnodek);
554  cosnok=cos(xnodek);
555  xmx=-sinnok*cosik;
556  xmy=cosnok*cosik;
557  ux=xmx*sinuk+cosnok*cosuk;
558  uy=xmy*sinuk+sinnok*cosuk;
559  uz=sinik*sinuk;
560  vx=xmx*cosuk-cosnok*sinuk;
561  vy=xmy*cosuk-sinnok*sinuk;
562  vz=sinik*cosuk;
563 
564  /* position and velocity */
565  x=rk*ux;
566  y=rk*uy;
567  z=rk*uz;
568  xdot=rdotk*ux+rfdotk*vx;
569  ydot=rdotk*uy+rfdotk*vy;
570  zdot=rdotk*uz+rfdotk*vz;
571 
572  rs[0]=x*XKMPER/AE*1E3; /* (m) */
573  rs[1]=y*XKMPER/AE*1E3;
574  rs[2]=z*XKMPER/AE*1E3;
575  rs[3]=xdot*XKMPER/AE*XMNPDA/86400.0*1E3; /* (m/s) */
576  rs[4]=ydot*XKMPER/AE*XMNPDA/86400.0*1E3;
577  rs[5]=zdot*XKMPER/AE*XMNPDA/86400.0*1E3;
578 }
579 /* drop spaces at string tail ------------------------------------------------*/
580 static void chop(char *buff)
581 {
582  int i;
583  for (i=strlen(buff)-1;i>=0;i--) {
584  if (buff[i]==' '||buff[i]=='\r'||buff[i]=='\n') buff[i]='\0';
585  else break;
586  }
587 }
588 /* test TLE line checksum ----------------------------------------------------*/
589 static int checksum(const char *buff)
590 {
591  int i,cs=0;
592 
593  if (strlen(buff)<69) return 0;
594 
595  for (i=0;i<68;i++) {
596  if ('0'<=buff[i]&&buff[i]<='9') cs+=(int)(buff[i]-'0');
597  else if (buff[i]=='-') cs+=1;
598  }
599  return (int)(buff[68]-'0')==cs%10;
600 }
601 /* decode TLE line 1 ---------------------------------------------------------*/
602 static int decode_line1(const char *buff, tled_t *data)
603 {
604  double year,doy,nddot,exp1,bstar,exp2,ep[6]={2000,1,1};
605 
606  strncpy(data->satno,buff+2,5); /* satellite number */
607  data->satno[5]='\0';
608  chop(data->satno);
609 
610  data->satclass=buff[7]; /* satellite classification */
611  strncpy(data->desig,buff+9,8); /* international designator */
612  data->desig[8]='\0';
613  chop(data->desig);
614 
615  year =str2num(buff,18, 2); /* epoch year */
616  doy =str2num(buff,20,12); /* epoch day of year */
617  data->ndot=str2num(buff,33,10); /* 1st time derivative of n */
618  nddot =str2num(buff,44, 6); /* 2nd time derivative of n */
619  exp1 =str2num(buff,50, 2);
620  bstar =str2num(buff,53, 6); /* Bstar drag term */
621  exp2 =str2num(buff,59, 2);
622  data->etype=(int)str2num(buff,62,1); /* ephemeris type */
623  data->eleno=(int)str2num(buff,64,4); /* ephemeris number */
624  data->nddot=nddot*1E-5*pow(10.0,exp1);
625  data->bstar=bstar*1E-5*pow(10.0,exp2);
626 
627  ep[0]=year+(year<57.0?2000.0:1900.0);
628  data->epoch=timeadd(epoch2time(ep),(doy-1.0)*86400.0);
629 
630  data->inc=data->OMG=data->ecc=data->omg=data->M=data->n=0.0;
631  data->rev=0;
632  return 1;
633 }
634 /* decode TLE line 2 ---------------------------------------------------------*/
635 static int decode_line2(const char *buff, tled_t *data)
636 {
637  char satno[16];
638 
639  strncpy(satno,buff+2,5); /* satellite number */
640  satno[5]='\0';
641  chop(satno);
642 
643  data->inc=str2num(buff, 8, 8); /* inclination (deg) */
644  data->OMG=str2num(buff,17, 8); /* RAAN (deg) */
645  data->ecc=str2num(buff,26, 7)*1E-7; /* eccentricity */
646  data->omg=str2num(buff,34, 8); /* argument of perigee (deg) */
647  data->M =str2num(buff,43, 8); /* mean anomaly (deg) */
648  data->n =str2num(buff,52,11); /* mean motion (rev/day) */
649  data->rev=(int)str2num(buff,63,5); /* revolution number */
650 
651  if (strcmp(satno,data->satno)) {
652  trace(2,"tle satno mismatch: %s %s\n",data->satno,satno);
653  return 0;
654  }
655  if (data->n<=0.0||data->ecc<0.0) {
656  trace(2,"tle data error: %s\n",satno);
657  return 0;
658  }
659  return 1;
660 }
661 /* add TLE data --------------------------------------------------------------*/
662 static int add_data(tle_t *tle, const tled_t *data)
663 {
664  tled_t *tle_data;
665 
666  if (tle->n>=tle->nmax) {
667  tle->nmax=tle->nmax<=0?1024:tle->nmax*2;
668 
669  if (!(tle_data=(tled_t *)realloc(tle->data,sizeof(tled_t)*tle->nmax))) {
670  trace(1,"tle malloc error\n");
671  free(tle->data); tle->data=NULL; tle->n=tle->nmax=0;
672  return 0;
673  }
674  tle->data=tle_data;
675  }
676  tle->data[tle->n++]=*data;
677  return 1;
678 }
679 /* compare TLE data by satellite name ----------------------------------------*/
680 static int cmp_tle_data(const void *p1, const void *p2)
681 {
682  const tled_t *q1=(const tled_t *)p1,*q2=(const tled_t *)p2;
683  return strcmp(q1->name,q2->name);
684 }
685 
686 int tle_read(const char *file, tle_t *tle)
687 {
688  FILE *fp;
689  tled_t data={{0}};
690  char *p,buff[256];
691  int line=0;
692 
693  if (!(fp=fopen(file,"r"))) {
694  trace(2,"tle file open error: %s\n",file);
695  return 0;
696  }
697  while (fgets(buff,sizeof(buff),fp)) {
698 
699  /* delete comments */
700  if ((p=strchr(buff,'#'))) *p='\0';
701  chop(buff);
702 
703  if (buff[0]=='1'&&checksum(buff)) {
704 
705  /* decode TLE line 1 */
706  if (decode_line1(buff,&data)) line=1;
707  }
708  else if (line==1&&buff[0]=='2'&&checksum(buff)) {
709 
710  /* decode TLE line 2 */
711  if (!decode_line2(buff,&data)) continue;
712 
713  /* add TLE data */
714  if (!add_data(tle,&data)) {
715  fclose(fp);
716  return 0;
717  }
718  data.name[0]='\0';
719  data.alias[0]='\0';
720  }
721  else if (buff[0]) {
722 
723  /* satellite name in three line format */
724  strcpy(data.name,buff);
725 
726  /* omit words in parentheses */
727  if ((p=strchr(data.name,'('))) *p='\0';
728  chop(data.name);
729  line=0;
730  }
731  }
732  fclose(fp);
733 
734  /* sort tle data by satellite name */
735  if (tle->n>0) qsort(tle->data,tle->n,sizeof(tled_t),cmp_tle_data);
736  return 1;
737 }
738 
739 int tle_pos(gtime_t time, const char *name, const char *satno,
740  const char *desig, const tle_t *tle, const erp_t *erp,
741  double *rs)
742 {
743  gtime_t tutc;
744  double tsince,rs_tle[6],rs_pef[6],gmst;
745  double R1[9]={0},R2[9]={0},R3[9]={0},W[9],erpv[5]={0};
746  int i=0,j,k,stat=1;
747 
748  /* binary search by satellite name */
749  if (*name) {
750  for (i=j=0,k=tle->n-1;j<=k;) {
751  i=(j+k)/2;
752  if (!(stat=strcmp(name,tle->data[i].name))) break;
753  if (stat<0) k=i-1; else j=i+1;
754  }
755  }
756  /* serial search by catalog no or international designator */
757  if (stat&&(*satno||*desig)) {
758  for (i=0;i<tle->n;i++) {
759  if (!strcmp(tle->data[i].satno,satno)||
760  !strcmp(tle->data[i].desig,desig)) break;
761  }
762  if (i<tle->n) stat=0;
763  }
764  if (stat) {
765  trace(3,"no tle data: name=%s satno=%s desig=%s\n",name,satno,desig);
766  return 0;
767  }
768  tutc=gpst2utc(time);
769 
770  /* time since epoch (min) */
771  tsince=timediff(tutc,tle->data[i].epoch)/60.0;
772 
773  /* SGP4 model propagator by STR#3 */
774  SGP4_STR3(tsince,tle->data+i,rs_tle);
775 
776  /* erp values */
777  if (erp) geterp(erp,time,erpv);
778 
779  /* GMST (rad) */
780  gmst=utc2gmst(tutc,erpv[2]);
781 
782  /* TEME (true equator, mean eqinox) -> ECEF (ref [2] IID, Appendix C) */
783  R1[0]=1.0; R1[4]=R1[8]=cos(-erpv[1]); R1[7]=sin(-erpv[1]); R1[5]=-R1[7];
784  R2[4]=1.0; R2[0]=R2[8]=cos(-erpv[0]); R2[2]=sin(-erpv[0]); R2[6]=-R2[2];
785  R3[8]=1.0; R3[0]=R3[4]=cos(gmst); R3[3]=sin(gmst); R3[1]=-R3[3];
786  matmul("NN",3,1,3,1.0,R3,rs_tle ,0.0,rs_pef );
787  matmul("NN",3,1,3,1.0,R3,rs_tle+3,0.0,rs_pef+3);
788  rs_pef[3]+=OMGE*rs_pef[1];
789  rs_pef[4]-=OMGE*rs_pef[0];
790  matmul("NN",3,3,3,1.0,R1,R2,0.0,W);
791  matmul("NN",3,1,3,1.0,W,rs_pef ,0.0,rs );
792  matmul("NN",3,1,3,1.0,W,rs_pef+3,0.0,rs+3);
793  return 1;
794 }
CK2
#define CK2
Definition: tle.c:345
XMNPDA
#define XMNPDA
Definition: tle.c:343
timeadd
gtime_t timeadd(gtime_t t, double sec)
Definition: tle.c:123
erpd_t::ut1_utc
double ut1_utc
Definition: tle.h:71
SGP4_STR3
static void SGP4_STR3(double tsince, const tled_t *data, double *rs)
Definition: tle.c:350
tle_read
int tle_read(const char *file, tle_t *tle)
Definition: tle.c:686
erpd_t::lod
double lod
Definition: tle.h:72
PI
#define PI
Definition: tle.c:65
mjd
mjd
file
page HOWTO subpage DoxygenGuide Documenting Your Code page DoxygenGuide Documenting Your Code todo Flesh out this document section doctips Tips for Documenting When defining make sure that the prototype is identical between the cpp and hpp file
day
day
gpst2utc
gtime_t gpst2utc(gtime_t t)
Definition: tle.c:167
year
year
tle.h
s
XmlRpcServer s
tle_t
Definition: tle.h:101
XKE
#define XKE
Definition: tle.c:341
QOMS2T
#define QOMS2T
Definition: tle.c:347
erpd_t::xpr
double xpr
Definition: tle.h:70
erpd_t::ypr
double ypr
Definition: tle.h:70
MAXLEAPS
#define MAXLEAPS
Definition: tle.c:90
gtime_t::sec
double sec
Definition: tle.h:64
utc2gpst
gtime_t utc2gpst(gtime_t t)
Definition: tle.c:179
XKMPER
#define XKMPER
Definition: tle.c:342
NULL
#define NULL
erpd_t::yp
double yp
Definition: tle.h:69
gtime_t::time
time_t time
Definition: tle.h:63
data
data
f
f
AE
#define AE
Definition: tle.c:344
sin
double sin(gnsstk::Angle x)
decode_line2
static int decode_line2(const char *buff, tled_t *data)
Definition: tle.c:635
time2epoch
void time2epoch(gtime_t t, double *ep)
Definition: tle.c:248
temp
temp
OMGE
#define OMGE
Definition: tle.c:64
time2sec
static double time2sec(gtime_t time, gtime_t *day)
Definition: tle.c:267
E6A
#define E6A
Definition: tle.c:337
y
page HOWTO subpage DoxygenGuide Documenting Your Code page DoxygenGuide Documenting Your Code todo Flesh out this document section doctips Tips for Documenting When defining make sure that the prototype is identical between the cpp and hpp including both the namespaces and the parameter names for you have std::string as the return type in the hpp file and string as the return type in the cpp Doxygen may get confused and autolink to the cpp version with no documentation If you don t use the same parameter names between the cpp and hpp that will also confuse Doxygen Don t put type information in return or param documentation It doesn t really add anything and will often cause Doxygen to complain and not produce the documentation< br > use note Do not put a comma after a param name unless you mean to document multiple parameters< br/> the output stream</code >< br/> y
add_data
static int add_data(tle_t *tle, const tled_t *data)
Definition: tle.c:662
tle_pos
int tle_pos(gtime_t time, const char *name, const char *satno, const char *desig, const tle_t *tle, const erp_t *erp, double *rs)
Definition: tle.c:739
tle_t::data
tled_t * data
Definition: tle.h:103
decode_line1
static int decode_line1(const char *buff, tled_t *data)
Definition: tle.c:602
gtime_t
Definition: tle.h:62
time
time
cmp_tle_data
static int cmp_tle_data(const void *p1, const void *p2)
Definition: tle.c:680
str2num
double str2num(const char *s, int i, int n)
Definition: tle.c:324
d
d
S
#define S
Definition: tle.c:348
tled_t::satno
char satno[16]
Definition: tle.h:83
erpd_t::mjd
double mjd
Definition: tle.h:68
cos
double cos(gnsstk::Angle x)
beta
double beta(double x, double y)
trace
void trace(int level, const char *format,...)
Definition: tle.c:113
DE2RA
#define DE2RA
Definition: tle.c:336
tle_t::n
int n
Definition: tle.h:102
tled_t::epoch
gtime_t epoch
Definition: tle.h:86
timediff
double timediff(gtime_t t1, gtime_t t2)
Definition: tle.c:135
tle_t::nmax
int nmax
Definition: tle.h:102
epoch2time
gtime_t epoch2time(const double *ep)
Definition: tle.c:145
tled_t::desig
char desig[16]
Definition: tle.h:85
chop
static void chop(char *buff)
Definition: tle.c:580
leaps
static double leaps[MAXLEAPS+1][7]
Definition: tle.c:91
int
int
erp_t::data
erpd_t * data
Definition: tle.h:77
TWOPI
#define TWOPI
Definition: tle.c:339
matmul
void matmul(const char *tr, int n, int k, int m, double alpha, const double *A, const double *B, double beta, double *C)
Definition: tle.c:300
checksum
static int checksum(const char *buff)
Definition: tle.c:589
utc2gmst
double utc2gmst(gtime_t t, double ut1_utc)
Definition: tle.c:283
TOTHRD
#define TOTHRD
Definition: tle.c:338
CK4
#define CK4
Definition: tle.c:346
XJ3
#define XJ3
Definition: tle.c:340
erp_t::n
int n
Definition: tle.h:76
t
geometry_msgs::TransformStamped t
geterp
int geterp(const erp_t *erp, gtime_t time, double *erpv)
Definition: tle.c:196
erpd_t::xp
double xp
Definition: tle.h:69
tled_t::name
char name[32]
Definition: tle.h:81
tled_t
Definition: tle.h:80
erp_t
Definition: tle.h:75


gnss_info
Author(s): Martin Pecka
autogenerated on Fri Nov 24 2023 03:50:35