1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.gnss.attitude;
18
19 import org.hipparchus.Field;
20 import org.hipparchus.RealFieldElement;
21 import org.hipparchus.util.FastMath;
22 import org.orekit.frames.Frame;
23 import org.orekit.time.AbsoluteDate;
24 import org.orekit.utils.ExtendedPVCoordinatesProvider;
25 import org.orekit.utils.TimeStampedAngularCoordinates;
26 import org.orekit.utils.TimeStampedFieldAngularCoordinates;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 public class GPSBlockIIA extends AbstractGNSSAttitudeProvider {
42
43
44 public static final double[] DEFAULT_YAW_RATES = new double[] {
45 Double.NaN,
46 FastMath.toRadians(0.1211), FastMath.toRadians(0.1339), FastMath.toRadians(0.1230), FastMath.toRadians(0.1233),
47 FastMath.toRadians(0.1180), FastMath.toRadians(0.1266), FastMath.toRadians(0.1269), FastMath.toRadians(0.1033),
48 FastMath.toRadians(0.1278), FastMath.toRadians(0.0978), FastMath.toRadians(0.2000), FastMath.toRadians(0.1990),
49 FastMath.toRadians(0.2000), FastMath.toRadians(0.0815), FastMath.toRadians(0.1303), FastMath.toRadians(0.0838),
50 FastMath.toRadians(0.1401), FastMath.toRadians(0.1069), FastMath.toRadians(0.0980), FastMath.toRadians(0.1030),
51 FastMath.toRadians(0.1366), FastMath.toRadians(0.1025), FastMath.toRadians(0.1140), FastMath.toRadians(0.1089),
52 FastMath.toRadians(0.1001), FastMath.toRadians(0.1227), FastMath.toRadians(0.1194), FastMath.toRadians(0.1260),
53 FastMath.toRadians(0.1228), FastMath.toRadians(0.1165), FastMath.toRadians(0.0969), FastMath.toRadians(0.1140)
54 };
55
56
57 public static final double DEFAULT_YAW_BIAS = FastMath.toRadians(0.5);
58
59
60 private static final long serialVersionUID = 20171114L;
61
62
63 private static final double NIGHT_TURN_LIMIT = FastMath.toRadians(180.0 - 13.25);
64
65
66 private final double END_MARGIN = 1800.0;
67
68
69 private final double yawRate;
70
71
72 private final double yawBias;
73
74
75
76
77
78
79
80
81
82
83
84
85 @Deprecated
86 public GPSBlockIIA(final double yawRate, final double yawBias,
87 final AbsoluteDateDate">AbsoluteDate validityStart, final AbsoluteDate validityEnd,
88 final ExtendedPVCoordinatesProvider sun, final Frame inertialFrame, final int prnNumber) {
89 this(yawRate, yawBias, validityStart, validityEnd, sun, inertialFrame);
90 }
91
92
93
94
95
96
97
98
99
100
101 public GPSBlockIIA(final double yawRate, final double yawBias,
102 final AbsoluteDateDate">AbsoluteDate validityStart, final AbsoluteDate validityEnd,
103 final ExtendedPVCoordinatesProvider sun, final Frame inertialFrame) {
104 super(validityStart, validityEnd, sun, inertialFrame);
105 this.yawRate = yawRate;
106 this.yawBias = yawBias;
107 }
108
109
110 @Override
111 protected TimeStampedAngularCoordinates correctedYaw(final GNSSAttitudeContext context) {
112
113
114 final double aNoon = FastMath.atan(context.getMuRate() / yawRate);
115 final double aNight = NIGHT_TURN_LIMIT;
116 final double cNoon = FastMath.cos(aNoon);
117 final double cNight = FastMath.cos(aNight);
118
119 if (context.setUpTurnRegion(cNight, cNoon)) {
120
121 final double absBeta = FastMath.abs(context.beta(context.getDate()));
122 context.setHalfSpan(context.inSunSide() ?
123 absBeta * FastMath.sqrt(aNoon / absBeta - 1.0) :
124 context.inOrbitPlaneAbsoluteAngle(aNight - FastMath.PI),
125 END_MARGIN);
126 if (context.inTurnTimeRange()) {
127
128
129 final double beta = context.getSecuredBeta();
130 final double phiStart = context.getYawStart(beta);
131 final double dtStart = context.timeSinceTurnStart();
132 final double linearPhi;
133 final double phiDot;
134 if (context.inSunSide()) {
135
136 if (beta > 0 && beta < yawBias) {
137
138
139 phiDot = FastMath.copySign(yawRate, beta);
140 linearPhi = phiStart + phiDot * dtStart;
141 } else {
142
143 phiDot = -FastMath.copySign(yawRate, beta);
144 linearPhi = phiStart + phiDot * dtStart;
145 }
146 } else {
147
148 phiDot = yawRate;
149 linearPhi = phiStart + phiDot * dtStart;
150 }
151
152 if (context.linearModelStillActive(linearPhi, phiDot)) {
153
154 return context.turnCorrectedAttitude(linearPhi, phiDot);
155 }
156
157 }
158
159 }
160
161
162 return context.nominalYaw(context.getDate());
163
164 }
165
166
167 @Override
168 protected <T extends RealFieldElement<T>> TimeStampedFieldAngularCoordinates<T> correctedYaw(final GNSSFieldAttitudeContext<T> context) {
169
170 final Field<T> field = context.getDate().getField();
171
172
173 final T aNoon = FastMath.atan(context.getMuRate().divide(yawRate));
174 final T aNight = field.getZero().add(NIGHT_TURN_LIMIT);
175 final double cNoon = FastMath.cos(aNoon.getReal());
176 final double cNight = FastMath.cos(aNight.getReal());
177
178 if (context.setUpTurnRegion(cNight, cNoon)) {
179
180 final T absBeta = FastMath.abs(context.beta(context.getDate()));
181 context.setHalfSpan(context.inSunSide() ?
182 absBeta.multiply(FastMath.sqrt(aNoon.divide(absBeta).subtract(1.0))) :
183 context.inOrbitPlaneAbsoluteAngle(aNight.subtract(FastMath.PI)),
184 END_MARGIN);
185 if (context.inTurnTimeRange()) {
186
187
188 final T beta = context.getSecuredBeta();
189 final T phiStart = context.getYawStart(beta);
190 final T dtStart = context.timeSinceTurnStart();
191 final T linearPhi;
192 final T phiDot;
193 if (context.inSunSide()) {
194
195 if (beta.getReal() > 0 && beta.getReal() < yawBias) {
196
197
198 phiDot = field.getZero().add(FastMath.copySign(yawRate, beta.getReal()));
199 linearPhi = phiStart.add(phiDot.multiply(dtStart));
200 } else {
201
202 phiDot = field.getZero().add(-FastMath.copySign(yawRate, beta.getReal()));
203 linearPhi = phiStart.add(phiDot.multiply(dtStart));
204 }
205 } else {
206
207 phiDot = field.getZero().add(yawRate);
208 linearPhi = phiStart.add(phiDot.multiply(dtStart));
209 }
210
211 if (context.linearModelStillActive(linearPhi, phiDot)) {
212
213 return context.turnCorrectedAttitude(linearPhi, phiDot);
214 }
215
216 }
217
218 }
219
220
221 return context.nominalYaw(context.getDate());
222
223 }
224
225 }