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.CalculusFieldElement;
21 import org.hipparchus.analysis.CalculusFieldUnivariateFunction;
22 import org.hipparchus.analysis.UnivariateFunction;
23 import org.hipparchus.analysis.solvers.AllowedSolution;
24 import org.hipparchus.analysis.solvers.BracketingNthOrderBrentSolver;
25 import org.hipparchus.analysis.solvers.FieldBracketingNthOrderBrentSolver;
26 import org.hipparchus.analysis.solvers.UnivariateSolverUtils;
27 import org.hipparchus.util.FastMath;
28 import org.orekit.frames.Frame;
29 import org.orekit.time.AbsoluteDate;
30 import org.orekit.utils.ExtendedPositionProvider;
31 import org.orekit.utils.TimeStampedAngularCoordinates;
32 import org.orekit.utils.TimeStampedFieldAngularCoordinates;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class Glonass extends AbstractGNSSAttitudeProvider {
48
49
50 public static final double DEFAULT_YAW_RATE = FastMath.toRadians(0.250);
51
52
53 private static final double NIGHT_TURN_LIMIT = FastMath.toRadians(180.0 - 14.20);
54
55
56 private static final double YAW_END_ZERO = FastMath.toRadians(75.0);
57
58
59 private static final double END_MARGIN = 0.0;
60
61
62 private final double yawRate;
63
64
65
66
67
68
69
70
71 public Glonass(final double yawRate,
72 final AbsoluteDate validityStart, final AbsoluteDate validityEnd,
73 final ExtendedPositionProvider sun, final Frame inertialFrame) {
74 super(validityStart, validityEnd, sun, inertialFrame);
75 this.yawRate = yawRate;
76 }
77
78
79 @Override
80 protected TimeStampedAngularCoordinates correctedYaw(final GNSSAttitudeContext context) {
81
82
83 final double realBeta = context.beta(context.getDate());
84 final double muRate = context.getMuRate();
85 final double aNight = NIGHT_TURN_LIMIT;
86 double aNoon = FastMath.atan(muRate / yawRate);
87 if (FastMath.abs(realBeta) < aNoon) {
88 final UnivariateFunction f = yawEnd -> {
89 final double delta = muRate * yawEnd / yawRate;
90 return yawEnd - 0.5 * FastMath.abs(context.computePhi(realBeta, delta) -
91 context.computePhi(realBeta, -delta));
92 };
93 final double[] bracket = UnivariateSolverUtils.bracket(f, YAW_END_ZERO, 0.0, FastMath.PI);
94 final double yawEnd = new BracketingNthOrderBrentSolver(1.0e-14, 1.0e-8, 1.0e-15, 5).
95 solve(50, f, bracket[0], bracket[1], AllowedSolution.ANY_SIDE);
96 aNoon = muRate * yawEnd / yawRate;
97 }
98
99 final double cNoon = FastMath.cos(aNoon);
100 final double cNight = FastMath.cos(aNight);
101
102 if (context.setUpTurnRegion(cNight, cNoon)) {
103
104 context.setHalfSpan(context.inSunSide() ?
105 aNoon :
106 context.inOrbitPlaneAbsoluteAngle(aNight - FastMath.PI),
107 END_MARGIN);
108 if (context.inTurnTimeRange()) {
109
110
111 final double beta = context.getSecuredBeta();
112 final double phiStart = context.getYawStart(beta);
113 final double dtStart = context.timeSinceTurnStart();
114
115 final double phiDot;
116 final double linearPhi;
117 final double phiEnd = context.getYawEnd(beta);
118 if (context.inSunSide()) {
119
120 phiDot = -FastMath.copySign(yawRate, beta);
121 linearPhi = phiStart + phiDot * dtStart;
122 } else {
123
124 phiDot = FastMath.copySign(yawRate, beta);
125 linearPhi = phiStart + phiDot * dtStart;
126
127 if (phiEnd / linearPhi < 0 || phiEnd / linearPhi > 1) {
128
129
130 return context.turnCorrectedAttitude(phiEnd, 0.0);
131 }
132
133 }
134
135 return context.turnCorrectedAttitude(linearPhi, phiDot);
136
137 }
138
139 }
140
141
142 return context.nominalYaw(context.getDate());
143
144 }
145
146
147 @Override
148 protected <T extends CalculusFieldElement<T>> TimeStampedFieldAngularCoordinates<T> correctedYaw(final GNSSFieldAttitudeContext<T> context) {
149
150 final Field<T> field = context.getDate().getField();
151
152
153 final T realBeta = context.beta(context.getDate());
154 final T muRate = context.getMuRate();
155 final T aNight = field.getZero().newInstance(NIGHT_TURN_LIMIT);
156 T aNoon = FastMath.atan(muRate.divide(yawRate));
157 if (FastMath.abs(realBeta).getReal() < aNoon.getReal()) {
158 final CalculusFieldUnivariateFunction<T> f = yawEnd -> {
159 final T delta = muRate.multiply(yawEnd).divide(yawRate);
160 return yawEnd.subtract(FastMath.abs(context.computePhi(realBeta, delta).
161 subtract(context.computePhi(realBeta, delta.negate()))).
162 multiply(0.5));
163 };
164 final T[] bracket = UnivariateSolverUtils.bracket(f, field.getZero().newInstance(YAW_END_ZERO),
165 field.getZero(), field.getZero().getPi());
166 final T yawEnd = new FieldBracketingNthOrderBrentSolver<>(field.getZero().newInstance(1.0e-14),
167 field.getZero().newInstance(1.0e-8),
168 field.getZero().newInstance(1.0e-15),
169 5).
170 solve(50, f, bracket[0], bracket[1], AllowedSolution.ANY_SIDE);
171 aNoon = muRate.multiply(yawEnd).divide(yawRate);
172 }
173
174 final double cNoon = FastMath.cos(aNoon.getReal());
175 final double cNight = FastMath.cos(aNight.getReal());
176
177 if (context.setUpTurnRegion(cNight, cNoon)) {
178
179 context.setHalfSpan(context.inSunSide() ?
180 aNoon :
181 context.inOrbitPlaneAbsoluteAngle(aNight.subtract(aNight.getPi())),
182 END_MARGIN);
183 if (context.inTurnTimeRange()) {
184
185
186 final T beta = context.getSecuredBeta();
187 final T phiStart = context.getYawStart(beta);
188 final T dtStart = context.timeSinceTurnStart();
189
190 final T phiDot;
191 final T linearPhi;
192 final T phiEnd = context.getYawEnd(beta);
193 if (context.inSunSide()) {
194
195 phiDot = field.getZero().newInstance(-FastMath.copySign(yawRate, beta.getReal()));
196 linearPhi = phiStart.add(phiDot.multiply(dtStart));
197 } else {
198
199 phiDot = field.getZero().newInstance(FastMath.copySign(yawRate, beta.getReal()));
200 linearPhi = phiStart.add(phiDot.multiply(dtStart));
201
202
203
204 if (phiEnd.getReal() / linearPhi.getReal() < 0 || phiEnd.getReal() / linearPhi.getReal() > 1) {
205 return context.turnCorrectedAttitude(phiEnd, field.getZero());
206 }
207
208 }
209
210 return context.turnCorrectedAttitude(linearPhi, phiDot);
211
212
213 }
214
215 }
216
217
218 return context.nominalYaw(context.getDate());
219
220 }
221
222 }