1 //==============================================================================
2 //
3 //  This file is part of GPSTk, the GPS Toolkit.
4 //
5 //  The GPSTk is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU Lesser General Public License as published
7 //  by the Free Software Foundation; either version 3.0 of the License, or
8 //  any later version.
9 //
10 //  The GPSTk is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU Lesser General Public License for more details.
14 //
15 //  You should have received a copy of the GNU Lesser General Public
16 //  License along with GPSTk; if not, write to the Free Software Foundation,
17 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 //  This software was developed by Applied Research Laboratories at the
20 //  University of Texas at Austin.
21 //  Copyright 2004-2020, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 //  This software was developed by Applied Research Laboratories at the
28 //  University of Texas at Austin, under contract to an agency or agencies
29 //  within the U.S. Department of Defense. The U.S. Government retains all
30 //  rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 //  Pursuant to DoD Directive 523024
33 //
34 //  DISTRIBUTION STATEMENT A: This software has been approved for public
35 //                            release, distribution is unlimited.
36 //
37 //==============================================================================
38 
39 /**
40  * @file PhaseWindup.cpp
41  * Implement computations of phase windup, solar ephemeris, satellite attitude
42  * and eclipse at the satellite.
43  */
44 
45 // -----------------------------------------------------------------------------------
46 // GPSTk includes
47 #include "Matrix.hpp"
48 #include "GNSSconstants.hpp"             // DEG_TO_RAD
49 // geomatics
50 #include "PhaseWindup.hpp"
51 #include "SunEarthSatGeometry.hpp"
52 #include "SolarPosition.hpp"
53 #include <math.h>
54 
55 using namespace std;
56 
57 namespace gpstk
58 {
59 
60 // -----------------------------------------------------------------------------------
61 // Compute the phase windup, in cycles, given the time, the unit vector from receiver
62 // to transmitter, and the west and north unit vectors at the receiver, all in ECEF.
63 // YR is the West unit vector, XR is the North unit vector, at the receiver.
64 // shadow is the fraction of the sun's area not visible at the satellite.
65 // Previous value is needed to ensure continuity and prevent 1-cycle ambiguities.
PhaseWindup(double & prev,CommonTime & tt,Position & SV,Position & Rx2Tx,Position & YR,Position & XR,SolarSystem & SSEph,EarthOrientation & EO,double & shadow,bool isBlockR)66 double PhaseWindup(double& prev,         // previous return value
67                    CommonTime& tt,          // epoch of interest
68                    Position& SV,         // satellite position
69                    Position& Rx2Tx,      // unit vector from receiver to satellite
70                    Position& YR,         // west unit vector at receiver
71                    Position& XR,         // north unit vector at receiver
72                    SolarSystem& SSEph,   // solar system ephemeris
73                    EarthOrientation& EO, // earth orientation at tt
74                    double& shadow,       // fraction of sun not visible at satellite
75                    bool isBlockR)        // true for Block IIR satellites
76 {
77 try {
78    double d,windup;
79    Position DR,DT;
80    Position TR = -1.0 * Rx2Tx;         // transmitter to receiver
81 
82    // get satellite attitude
83    Position XT,YT,ZT;
84    Matrix<double> Att = SSEph.SatelliteAttitude(tt, SV);
85    XT = Position(Att(0,0),Att(0,1),Att(0,2));      // Cartesian is default
86    YT = Position(Att(1,0),Att(1,1),Att(1,2));
87    ZT = Position(Att(2,0),Att(2,1),Att(2,2));
88 
89    // NB. Block IIR has X (ie the effective dipole orientation) in the -XT direction.
90    // Ref. Kouba(2009) GPS Solutions 13, pp1-12.
91    // In fact it should be a rotation by pi about Z, producing a constant offset.
92    //if(isBlockR)
93    //{
94    //   XT = Position(-Att(0,0),-Att(0,1),-Att(0,2));
95    //   YT = Position(-Att(1,0),-Att(1,1),-Att(1,2));
96    //}
97 
98    // compute effective dipoles at receiver and transmitter
99    // Ref Kouba(2009) Using IGS Products; note sign diff. <=> East(ref) West(here)
100    // NB. switching second sign between the two eqns <=> overall sign windup
101    DR = XR - TR * TR.dot(XR) + Position(TR.cross(YR));
102    DT = XT - TR * TR.dot(XT) - Position(TR.cross(YT));
103 
104    // normalize
105    d  = 1.0/DR.mag();
106    DR = d * DR;
107    d  = 1.0/DT.mag();
108    DT = d * DT;
109 
110    windup = ::acos(DT.dot(DR)) / TWO_PI;             // cycles
111    if (TR.dot(DR.cross(DT)) < 0.) windup *= -1.0;
112 
113    // adjust by 2pi if necessary
114    d = windup-prev;
115    windup -= int(d + (d < 0.0 ? -0.5 : 0.5));
116 
117    return windup;
118 }
119 catch(Exception& e) { GPSTK_RETHROW(e); }
120 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
121 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
122 }
123 
124 // -----------------------------------------------------------------------------------
125 // Version without JPL solar system ephemeris - uses a lower quality solar position.
126 // Compute the phase windup, in cycles, given the time, the unit vector from receiver
127 // to transmitter, and the west and north unit vectors at the receiver, all in ECEF.
128 // YR is the West unit vector, XR is the North unit vector, at the receiver.
129 // shadow is the fraction of the sun's area not visible at the satellite.
PhaseWindup(double & prev,CommonTime & tt,Position & SV,Position & Rx2Tx,Position & YR,Position & XR,double & shadow,bool isBlockR)130 double PhaseWindup(double& prev,       // previous return value
131                    CommonTime& tt,        // epoch of interest
132                    Position& SV,       // satellite position
133                    Position& Rx2Tx,    // unit vector from receiver to satellite
134                    Position& YR,       // west unit vector at receiver
135                    Position& XR,       // north unit vector at receiver
136                    double& shadow,     // fraction of sun not visible at satellite
137                    bool isBlockR)      // true for Block IIR satellites
138 {
139 try {
140    double d,windup=0.0;
141    Position DR,DT;
142    Position TR = -1.0 * Rx2Tx;         // transmitter to receiver
143 
144    // get satellite attitude
145    Position XT,YT,ZT,Sun;
146    double AR;
147    Sun = SolarPosition(tt,AR);
148    Matrix<double> Att = SatelliteAttitude(SV,Sun);
149    XT = Position(Att(0,0),Att(0,1),Att(0,2));      // Cartesian is default
150    YT = Position(Att(1,0),Att(1,1),Att(1,2));
151    ZT = Position(Att(2,0),Att(2,1),Att(2,2));
152 
153    // NB. Block IIR has X (ie the effective dipole orientation) in the -XT direction.
154    // Ref. Kouba(2009) GPS Solutions 13, pp1-12.
155    if(isBlockR) XT = Position(-Att(0,0),-Att(0,1),-Att(0,2));
156 
157    // compute effective dipoles at receiver and transmitter
158    // Ref Kouba(2009) Using IGS Products; note sign diff. <=> East(ref) West(here)
159    // NB. switching second sign between the two eqns <=> overall sign windup
160    DR = XR - TR * TR.dot(XR) + Position(TR.cross(YR));
161    DT = XT - TR * TR.dot(XT) - Position(TR.cross(YT));
162 
163    // normalize
164    d  = 1.0/DR.mag();
165    DR = d * DR;
166    d  = 1.0/DT.mag();
167    DT = d * DT;
168 
169    windup = ::acos(DT.dot(DR)) / TWO_PI;
170    if (TR.dot(DR.cross(DT)) < 0.) windup *= -1.0;
171 
172    // adjust by 2pi if necessary
173    d = windup-prev;
174    windup -= int(d + (d < 0.0 ? -0.5 : 0.5));
175 
176    return windup;
177 }
178 catch(Exception& e) { GPSTK_RETHROW(e); }
179 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
180 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
181 }
182 
183 
184 } // end namespace gpstk
185 //------------------------------------------------------------------------------------
186 //------------------------------------------------------------------------------------
187