001    /*
002     * $Id: Kepler.java,v 1.3 2012/02/19 17:35:39 davep Exp $
003     *
004     * This file is part of McIDAS-V
005     *
006     * Copyright 2007-2012
007     * Space Science and Engineering Center (SSEC)
008     * University of Wisconsin - Madison
009     * 1225 W. Dayton Street, Madison, WI 53706, USA
010     * https://www.ssec.wisc.edu/mcidas
011     * 
012     * All Rights Reserved
013     * 
014     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015     * some McIDAS-V source code is based on IDV and VisAD source code.  
016     * 
017     * McIDAS-V is free software; you can redistribute it and/or modify
018     * it under the terms of the GNU Lesser Public License as published by
019     * the Free Software Foundation; either version 3 of the License, or
020     * (at your option) any later version.
021     * 
022     * McIDAS-V is distributed in the hope that it will be useful,
023     * but WITHOUT ANY WARRANTY; without even the implied warranty of
024     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025     * GNU Lesser Public License for more details.
026     * 
027     * You should have received a copy of the GNU Lesser Public License
028     * along with this program.  If not, see http://www.gnu.org/licenses.
029     */
030    // Shawn E. Gano
031    // Kepler routines
032    /**
033     * =====================================================================
034     * Copyright (C) 2009 Shawn E. Gano
035     * 
036     * This file is part of JSatTrak.
037     * 
038     * JSatTrak is free software: you can redistribute it and/or modify
039     * it under the terms of the GNU Lesser General Public License as published by
040     * the Free Software Foundation, either version 3 of the License, or
041     * (at your option) any later version.
042     * 
043     * JSatTrak is distributed in the hope that it will be useful,
044     * but WITHOUT ANY WARRANTY; without even the implied warranty of
045     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
046     * GNU Lesser General Public License for more details.
047     * 
048     * You should have received a copy of the GNU Lesser General Public License
049     * along with JSatTrak.  If not, see <http://www.gnu.org/licenses/>.
050     * =====================================================================
051     */
052    package edu.wisc.ssec.mcidasv.data.adde.sgp4;
053    
054    //import jsattrak.utilities.StateVector;
055    
056    public class Kepler
057    {
058            
059        /**
060         *  Overload for state
061         * @param GM Gravitational coefficient (gravitational constant * mass of central body)
062         * @param kepElements Keplarian elements (see other state function)
063         * @param dt Time since epoch (seconds?)
064         * @return State vector (x,y,z,vx,vy,vz)
065         */
066    /*
067        public static double[] state(double GM, double[] kepElements, double dt)
068        {
069            return state(GM, kepElements[0], kepElements[1],kepElements[2], kepElements[3], kepElements[4], kepElements[5], dt);
070        }
071    */    
072        /**
073         * Computes the satellite state vector from osculating Keplerian elements for elliptic orbits
074         * <p>Notes:
075         * <br> The semimajor axis a=Kep(0), dt and GM must be given in consistent units,
076         *      e.g. [m], [s] and [m^3/s^2]. The resulting units of length and velocity
077         *      are implied by the units of GM, e.g. [m] and [m/s].
078         *
079         * @param GM Gravitational coefficient (gravitational constant * mass of central body)
080         * @param a Semimajor axis
081         * @param e Eccentricity
082         * @param i Inclination [rad]
083         * @param Omega Longitude of the ascending node [rad] or is this RAAN? (I think it is RAAN)
084         * @param omega Argument of pericenter [rad]
085         * @param M0 Mean anomaly at epoch [rad]
086         * @param dt Time since epoch (seconds?)
087         * @return State vector (x,y,z,vx,vy,vz)
088         */
089    /*
090            public static double[] state(double GM, double a, double e, double i, double Omega, double omega, double M0, double dt)
091            {
092                    double M; // mean anomaly
093                    double n;
094                    double E, cosE, sinE; // eccentric anomaly
095                    double fac, R, V;
096    
097                    // vectors for position (r) and velocity (v)
098                    double[] r = new double[3];
099                    double[] v = new double[3];
100                    double[] state = new double[6]; // full state
101    
102                    // transformation matrices
103                    double[][] Rx = new double[3][3];
104                    // double[][] Ry = new double[3][3];
105                    double[][] Rz = new double[3][3];
106    
107                    // rotation matrix
108                    double[][] PQW = new double[3][3];
109    
110                    // Mean anomaly
111                    if (dt == 0.0)
112                    {
113                            M = M0;
114                    } else
115                    {
116                            n = Math.sqrt(GM / (a * a * a));
117                            M = M0 + n * dt;
118                    }
119    
120                    // Eccentric anomaly
121                    E = EccAnom(M, e);
122                    cosE = Math.cos(E);
123                    sinE = Math.sin(E);
124    
125                    // Perifocal coordinates
126                    fac = Math.sqrt((1.0 - e) * (1.0 + e));
127    
128                    R = a * (1.0 - e * cosE); // Distance
129                    V = Math.sqrt(GM * a) / R; // Velocity
130    
131                    // r
132                    r[0] = a * (cosE - e);
133                    r[1] = a * fac * sinE;
134                    r[2] = 0.0;
135    
136                    // v
137                    v[0] = -V * sinE;
138                    v[1] = +V * fac * cosE;
139                    v[2] = 0.0;
140    
141                    // Transformation to reference system (Gaussian vectors)
142                    Rx = MathUtils.R_x(-i);
143                    Rz = MathUtils.R_z(-Omega);
144    
145                    // PQW = R_z(-Omega) * R_x(-i) * R_z(-omega);
146                    PQW = MathUtils.mult(Rz, Rx);
147                    Rz = MathUtils.R_z(-omega);
148                    PQW = MathUtils.mult(PQW, Rz);
149    
150                    r = MathUtils.mult(PQW, r);
151                    v = MathUtils.mult(PQW, v);
152    
153                    // State vector
154                    state[0] = r[0];
155                    state[1] = r[1];
156                    state[2] = r[2];
157                    state[3] = v[0];
158                    state[4] = v[1];
159                    state[5] = v[2];
160    
161                    // return Stack(r,v);
162                    return state;
163    
164            } // state
165    */
166    
167        /**
168         * Computes the eccentric anomaly for elliptic orbits
169         *
170         * @param M Mean anomaly in [rad]
171         * @param e Eccentricity of the orbit [0,1]
172         * @return Eccentric anomaly in [rad]
173         */
174    /*
175            public static double EccAnom(double M, double e)
176            {
177    
178                    // Constants
179                    final int maxit = 15;
180                    final double eps = 100.0 * 2.22E-16; // JAVA FIND MACHINE PRECISION // 100.0*eps_mach
181    
182                    // Variables
183    
184                    int i = 0;
185                    double E, f;
186    
187                    // Starting value
188                    M = MathUtils.Modulo(M, 2.0 * Math.PI);
189                    if (e < 0.8)
190                            E = M;
191                    else
192                            E = Math.PI;
193    
194                    // Iteration
195                    do
196                    {
197                            f = E - e * Math.sin(E) - M;
198                            E = E - f / (1.0 - e * Math.cos(E));
199                            ++i;
200                            if (i == maxit)
201                            {
202                                    System.out.println(" convergence problems in EccAnom\n");
203                                    break;
204                            }
205                    } while (Math.abs(f) > eps);
206    
207                    return E;
208    
209            } // EccAnom
210    */
211            
212            /**
213             * Computes the osculating Keplerian elements from the satellite state vector for elliptic orbits for Earth
214             * @param StateVector j2K cartesian state vector object (t,x,y,z,dx,dy,dz)
215             * @return Keplerian elements (a,e,i,Omega,omega,M) see state function for element definitions
216             */
217    /*
218            public static double[] SingularOsculatingElementsEarth( StateVector state )
219            { 
220                double[] r = new double[] {state.state[1],state.state[2],state.state[3]};
221                double[] v = new double[] {state.state[4],state.state[5],state.state[6]};
222                
223                return SingularOsculatingElements( AstroConst.GM_Earth, r, v );
224            }
225    */       
226            /**
227             * Computes the osculating Keplerian elements from the satellite state vector for elliptic orbits
228             * @param GM Gravitational coefficient (gravitational constant * mass of central body)
229             * @param state j2K cartesian state vector (x,y,z,dx,dy,dz)
230             * @return Keplerian elements (a,e,i,Omega,omega,M) see state function for element definitions
231             */
232    /*
233            public static double[] SingularOsculatingElements( double GM, double[] state )
234            { 
235                double[] r = new double[] {state[0],state[1],state[2]};
236                double[] v = new double[] {state[3],state[4],state[5]};
237                
238                return SingularOsculatingElements( GM, r, v );
239            }
240    */        
241        /**
242         * Computes the osculating Keplerian elements from the satellite state vector for elliptic orbits
243         *
244         * @param GM Gravitational coefficient (gravitational constant * mass of central body)
245         * @param r State vector (x,y,z)
246         * @param v State vector (vx,vy,vz)
247         * @return Keplerian elements (a,e,i,Omega,omega,M) see state function for element definitions
248         */
249    /*
250            public static double[] SingularOsculatingElements( double GM, double[] r, double[] v )
251            { 
252                // Variables
253                
254                double[] h = new double[3];
255                double  H, u, R;
256                double  eCosE, eSinE, e2, E, nu;
257                double  a,e,i,Omega,omega,M;
258                            
259                h = MathUtils.cross(r,v);                         // Areal velocity
260                H = MathUtils.norm(h);
261                
262                Omega = Math.atan2( h[0], -h[1] );                     // Long. ascend. node
263                Omega = Omega % (Math.PI*2.0);
264                i     = Math.atan2( Math.sqrt(h[0]*h[0]+h[1]*h[1]), h[2] ); // Inclination
265                u     = Math.atan2( r[2]*H, -r[0]*h[1]+r[1]*h[0] );    // Arg. of latitude
266                
267                R  = MathUtils.norm(r);                                      // Distance
268                
269                //System.out.println("R="+R);
270                //System.out.println("v dot v="+(MathUtils.dot(v,v)));
271                //System.out.println("GM="+GM);
272                
273                a = 1.0 / (2.0/R-MathUtils.dot(v,v)/GM);                     // Semi-major axis
274                
275                eCosE = 1.0-R/a;                                   // e*cos(E)
276                eSinE = MathUtils.dot(r,v)/Math.sqrt(GM*a);                       // e*sin(E)
277                
278                e2 = eCosE*eCosE +eSinE*eSinE;
279                e  = Math.sqrt(e2);                                     // Eccentricity
280                E  = Math.atan2(eSinE,eCosE);                           // Eccentric anomaly
281                
282                M  = (E-eSinE)%(2.0*Math.PI);                          // Mean anomaly
283                
284                nu = Math.atan2(Math.sqrt(1.0-e2)*eSinE, eCosE-e2);          // True anomaly
285                
286                omega = (u-nu)%(2.0*Math.PI);                          // Arg. of perihelion
287                
288                // Keplerian elements vector
289                
290                //System.out.println("Real a = " + a);
291                
292                return (new double[] {a,e,i,Omega,omega,M});
293            } // SingularElements
294    */
295            
296        /**
297         * calculate oculating orbital period of a eliptical orbit from position and velocity
298         *
299         * @param GM Gravitational coefficient (gravitational constant * mass of central body)
300         * @param r State vector (x,y,z)
301         * @param v State vector (vx,vy,vz)
302         * @return oculating orbital period
303         */
304            public static double CalculatePeriod( double GM, double[] r, double[] v )
305            { 
306                double R  = MathUtils.norm(r); // current radius 
307                
308                double a = 1.0 / (2.0/R-MathUtils.dot(v,v)/GM);                     // Semi-major axis
309                
310                return ( 2.0*Math.PI*Math.sqrt(a*a*a/GM) );
311            } // CalculatePeriod
312    
313    } // Kepler