source: Sophya/trunk/SophyaExt/XephemAstroLib/twobody.c@ 1895

Last change on this file since 1895 was 1719, checked in by cmv, 24 years ago

Adapted to version 3.5 xephem cmv 22/10/2001

File size: 6.4 KB
Line 
1/*
2 *
3 * TWOBODY.C
4 *
5 * Computation of planetary position, two-body computation
6 *
7 * Paul Schlyter, 1987-06-15
8 *
9 * Decreased EPSILON from 2E-4 to 3E-8, 1988-12-05
10 *
11 * 1990-01-01: Bug fix in almost parabolic orbits: now the routine
12 * doesn't bomb there (an if block was too large)
13 *
14 * 2000-12-06: Donated to Elwood Downey if he wants to use it in XEphem
15 */
16
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <math.h>
21
22
23/* Constants used when solving Kepler's equation */
24#define EPSILON 3E-8
25#define INFINITY 1E+10
26
27/* Math constants */
28#define PI 3.14159265358979323846
29#define RADEG ( 180.0 / PI )
30#define DEGRAD ( PI / 180.0 )
31
32/* Trig functions in degrees */
33#define sind(x) sin(x*DEGRAD)
34#define cosd(x) cos(x*DEGRAD)
35#define atand(x) (RADEG*atan(x))
36#define atan2d(y,x) (RADEG*atan2(y,x))
37
38/* Gauss' grav.-konstant */
39#define K 1.720209895E-2
40#define KD ( K * 180.0 / PI )
41#define K2 ( K / 2.0 )
42
43
44
45
46static double cubroot( double x )
47/* Cubic root */
48{
49 double a,b;
50
51 if ( x == 0.0 )
52 return 0.0;
53 else
54 {
55 a = fabs(x);
56 b = exp( log(a) / 3.0 );
57 return x > 0.0 ? b : -b;
58 }
59} /* cubroot */
60
61
62static double rev180( double ang )
63/* Normalize angle to between +180 and -180 degrees */
64{
65 return ang - 360.0 * floor(ang*(1.0/360.0) + 0.5);
66} /* rev180 */
67
68
69
70static double kepler( double m, double ex )
71/*
72 * Solves Kepler's equation
73 * m = mean anomaly
74 * ex = eccentricity
75 * kepler = eccentric anomaly
76 */
77{
78 double m1, sinm, cosm, exd, exan, dexan, lim1, adko, adk, denom;
79 int converged;
80
81 m1 = rev180(m);
82 sinm = sind(m1);
83 cosm = cosd(m1);
84 /* 1st approximation: */
85 exan = atan2d(sinm,cosm-ex);
86 if ( ex > 0.008 )
87 { /* Iteration formula: */
88 exd = ex * RADEG;
89 lim1 = 1E-3 / ex;
90 adko = INFINITY;
91 denom = 1.0 - ex * cosd(exan);
92 do
93 {
94 dexan = (m1 + exd * sind(exan) - exan) / denom;
95 exan = exan + dexan;
96 adk = fabs(dexan);
97 converged = adk < EPSILON || adk >= adko ;
98 adko = adk;
99 if ( !converged && adk > lim1 )
100 denom = 1.0 - ex * cosd(exan);
101 } while ( !converged );
102 }
103 return exan;
104} /* kepler */
105
106
107static void vr( double *v, double *r, double m, double e, double a )
108/*
109 * Elliptic orbits only:
110 * computes: v = true anomaly (degrees)
111 * r = radius vector (a.u.)
112 * from: m = mean anomaly (degrees)
113 * e = eccentricity
114 * a = semimajor axis (a.u.)
115 */
116{
117 double ean, x, y;
118
119 ean = kepler(m,e);
120 x = a*(cosd(ean)-e);
121 y = a*sqrt(1.-e*e)*sind(ean);
122 *r = sqrt(x*x+y*y);
123 *v = atan2d(y,x);
124} /* vr */
125
126
127void vrc( double *v, double *r, double tp, double e, double q )
128/*
129 * Elliptic, hyperbolic and near-parabolic orbits:
130 * computes: v = true anomaly (degrees)
131 * r = radius vector (a.u.)
132 * from: tp = time from perihelion (days)
133 * e = eccentricity
134 * q = perihelion distance (a.u.)
135 */
136{
137
138 double lambda;
139
140 double a, b, w, w2, w4, c, c1, c2, c3, c5, a0, a1, a2,
141 a3, m, n, g, adgg, adgg2, gs, dg;
142
143 if ( tp == 0.0 ) /* In perihelion */
144 {
145 *v = 0.0;
146 *r = q;
147 return;
148 }
149
150
151 lambda = (1.0-e) / (1.0+e);
152
153 if ( fabs(lambda) < 0.01 )
154 { /* Near-parabolic orbits */
155 a = K2 * sqrt((1.0+e)/(q*q*q)) * tp;
156 b = sqrt( 1.0 + 2.25*a*a );
157 w = cubroot( b + 1.5*a ) - cubroot( b - 1.5*a );
158
159 /* Test if it's accuate enough to compute this as a near-parabolic orbit */
160 if ( fabs(w*w*lambda) > 0.2 )
161 {
162 if ( fabs(lambda) < 0.0002 )
163 {
164 /* Sorry, but we cannot compute this at all -- we must give up!
165 *
166 * This happens very rarely, in orbits having an eccentricity
167 * some 2% away from 1.0 AND if the body is very very far from
168 * perihelion. E.g. a Kreutz sun-grazing comet having
169 * eccentricity near 0.98 or 1.02, and being outside
170 * the orbit of Pluto. For any reasonable orbit this will
171 * never happen in practice.
172 *
173 * You might want to code a more graceful error exit here though.
174 *
175 */
176 printf( "\nNear-parabolic orbit: inaccurate result."
177 "\n e = %f, lambda = %f, w = %f", e, lambda, w );
178 exit(1);
179 }
180 else
181 {
182 /* We cannot compute this as a near-parabolic orbit, so let's
183 compute it as an elliptic or hyperbolic orbit instead. */
184 goto ellipse_hyperbola;
185 }
186 }
187
188 /* Go ahead computing the near-parabolic case */
189 c = 1.0 + 1.0 / (w*w);
190 c1 = 1.0 / c;
191 c2 = c1*c1;
192 c3 = c1*c2;
193 c5 = c3*c2;
194 w2 = w*w;
195 w4 = w2*w2;
196 a0 = w;
197 a1 = 2.0 * w * (0.33333333 + 0.2*w2) * c1;
198 a2 = 0.2 * w * (7.0 + 0.14285714 * (33.0*w2+7.4*w4)) * c3;
199 a3 = 0.022857143 * (108.0 + 37.177777*w2 + 5.1111111*w4) * c5;
200 w = (( lambda * a3 + a2 ) * lambda + a1 ) * lambda + a0;
201 w2 = w*w;
202 *v = 2.0 * atand(w);
203 *r = q * (1+w2) / ( 1.0 + w2*lambda );
204 return; /* Near-parabolic orbit */
205 }
206
207
208ellipse_hyperbola:
209
210 if ( lambda > 0.0 )
211 { /* Elliptic orbit: */
212 a = q / (1.0-e); /* Semi-major axis */
213 m = KD * tp / sqrt(a*a*a); /* Mean Anomaly */
214 vr( v, r, m, e, a ); /* Solve Kepler's equation, etc */
215 }
216 else
217 { /* Hyperbolic orbit: */
218 a = q / (e-1.0); /* Semi-major axis */
219 n = K * tp / sqrt(a*a*a); /* "Daily motion" */
220 g = n/e;
221 adgg = INFINITY;
222 do
223 {
224 adgg2 = adgg;
225 gs = sqrt(g*g+1.0);
226 dg = -( e*g - log(g+gs) - n ) / ( e - 1.0/gs );
227 g = g + dg;
228 adgg = fabs(dg/g);
229 } while ( adgg < adgg2 && adgg > 1E-5 );
230 gs = sqrt(g*g+1.0);
231 *v = 2.0 * atand( sqrt( (e+1.0)/(e-1.0) ) * g / (gs+1.0) );
232 *r = q * (1.0+e) / ( 1.0 + e*cosd(*v) );
233 }
234
235} /* vrc */
236
237/* For RCS Only -- Do Not Edit */
238static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: twobody.c,v $ $Date: 2001-10-22 12:08:28 $ $Revision: 1.1 $ $Name: not supported by cvs2svn $"};
Note: See TracBrowser for help on using the repository browser.