1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.estimation.measurements;
18
19 import java.util.Map;
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.hipparchus.Field;
23 import org.hipparchus.analysis.differentiation.Gradient;
24 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
25 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
27 import org.hipparchus.geometry.euclidean.threed.Vector3D;
28 import org.hipparchus.util.FastMath;
29 import org.orekit.bodies.BodyShape;
30 import org.orekit.bodies.FieldGeodeticPoint;
31 import org.orekit.bodies.GeodeticPoint;
32 import org.orekit.frames.FieldStaticTransform;
33 import org.orekit.frames.FieldTransform;
34 import org.orekit.frames.Frame;
35 import org.orekit.frames.KinematicTransform;
36 import org.orekit.frames.StaticTransform;
37 import org.orekit.frames.TopocentricFrame;
38 import org.orekit.frames.TopocentricTransformProvider;
39 import org.orekit.frames.Transform;
40 import org.orekit.models.earth.displacement.StationDisplacement;
41 import org.orekit.time.AbsoluteDate;
42 import org.orekit.time.FieldAbsoluteDate;
43 import org.orekit.time.clocks.QuadraticClockModel;
44 import org.orekit.utils.AngularCoordinates;
45 import org.orekit.utils.FieldAngularCoordinates;
46 import org.orekit.utils.FieldPVCoordinates;
47 import org.orekit.utils.FieldPVCoordinatesProvider;
48 import org.orekit.utils.PVCoordinatesProvider;
49 import org.orekit.utils.ParameterDriver;
50 import org.orekit.utils.TimeStampedFieldPVCoordinates;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public class GroundStation extends AbstractParticipant implements GroundObserver {
72
73
74
75
76
77
78
79 private static final double POSITION_OFFSET_SCALE = FastMath.scalb(1.0, 0);
80
81
82 private final TopocentricFrame baseFrame;
83
84
85 private final ParameterDriver eastOffsetDriver;
86
87
88 private final ParameterDriver northOffsetDriver;
89
90
91 private final ParameterDriver zenithOffsetDriver;
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public GroundStation(final TopocentricFrame baseFrame) {
107 this(baseFrame, createEmptyQuadraticClock(baseFrame.getName()));
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public GroundStation(final TopocentricFrame baseFrame, final QuadraticClockModel clock) {
125 super(baseFrame.getName(), clock);
126 this.baseFrame = baseFrame;
127
128 this.eastOffsetDriver = new ParameterDriver(baseFrame.getName() + OFFSET_SUFFIX + "-East",
129 0.0, POSITION_OFFSET_SCALE,
130 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
131
132 this.northOffsetDriver = new ParameterDriver(baseFrame.getName() + OFFSET_SUFFIX + "-North",
133 0.0, POSITION_OFFSET_SCALE,
134 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
135
136 this.zenithOffsetDriver = new ParameterDriver(baseFrame.getName() + OFFSET_SUFFIX + "-Zenith",
137 0.0, POSITION_OFFSET_SCALE,
138 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
139
140
141 addParameterDriver(this.eastOffsetDriver);
142 addParameterDriver(this.northOffsetDriver);
143 addParameterDriver(this.zenithOffsetDriver);
144
145 }
146
147 @Override
148 public BodyShape getParentShape() {
149 return getBaseFrame().getParentShape();
150 }
151
152
153
154
155 public ParameterDriver getEastOffsetDriver() {
156 return eastOffsetDriver;
157 }
158
159
160
161
162 public ParameterDriver getNorthOffsetDriver() {
163 return northOffsetDriver;
164 }
165
166
167
168
169 public ParameterDriver getZenithOffsetDriver() {
170 return zenithOffsetDriver;
171 }
172
173
174
175
176
177
178
179
180 public TopocentricFrame getBaseFrame() {
181 return baseFrame;
182 }
183
184
185
186
187
188
189
190
191 protected Vector3D computeDisplacement(final AbsoluteDate date, final Vector3D position) {
192 return Vector3D.ZERO;
193 }
194
195
196
197
198
199
200 public GeodeticPoint getOffsetGeodeticPoint(final AbsoluteDate date) {
201
202
203 final double x = eastOffsetDriver.getValue();
204 final double y = northOffsetDriver.getValue();
205 final double z = zenithOffsetDriver.getValue();
206 final BodyShape baseShape = baseFrame.getParentShape();
207 final StaticTransform baseToBody = baseFrame.getStaticTransformTo(baseShape.getBodyFrame(), date);
208 Vector3D origin = baseToBody.transformPosition(new Vector3D(x, y, z));
209
210 if (date != null) {
211 origin = origin.add(computeDisplacement(date, origin));
212 }
213
214 return baseShape.transform(origin, baseShape.getBodyFrame(), date);
215
216 }
217
218
219
220
221
222
223
224
225 public <T extends CalculusFieldElement<T>> FieldGeodeticPoint<T> getOffsetGeodeticPoint(final FieldAbsoluteDate<T> date) {
226
227
228 final double x = eastOffsetDriver.getValue();
229 final double y = northOffsetDriver.getValue();
230 final double z = zenithOffsetDriver.getValue();
231 final BodyShape baseShape = baseFrame.getParentShape();
232 final FieldStaticTransform<T> baseToBody = baseFrame.getStaticTransformTo(baseShape.getBodyFrame(), date);
233 FieldVector3D<T> origin = baseToBody.transformPosition(new Vector3D(x, y, z));
234 origin = origin.add(computeDisplacement(date.toAbsoluteDate(), origin.toVector3D()));
235
236 return baseShape.transform(origin, baseShape.getBodyFrame(), date);
237
238 }
239
240
241 @Override
242 public PVCoordinatesProvider getPVCoordinatesProvider() {
243 final GeodeticPoint offsetPoint = getOffsetGeodeticPoint(AbsoluteDate.ARBITRARY_EPOCH);
244 return new TopocentricFrame(baseFrame.getParentShape(), offsetPoint, "offset");
245 }
246
247
248 @Override
249 public FieldPVCoordinatesProvider<Gradient> getFieldPVCoordinatesProvider(final int freeParameters,
250 final Map<String, Integer> parameterIndices) {
251 return new FieldPVCoordinatesProvider<>() {
252 @Override
253 public TimeStampedFieldPVCoordinates<Gradient> getPVCoordinates(final FieldAbsoluteDate<Gradient> date,
254 final Frame frame) {
255
256 final FieldVector3D<Gradient> origin = getOrigin(date, parameterIndices);
257
258
259 final Transform bodyToInertNonField = baseFrame.getParent().getTransformTo(frame, date.toAbsoluteDate());
260 final FieldTransform<Gradient> bodyToInert = new FieldTransform<>(date.getField(),
261 bodyToInertNonField).shiftedBy(date.durationFrom(date.toAbsoluteDate()));
262
263 final TimeStampedFieldPVCoordinates<Gradient> zeroPV = new TimeStampedFieldPVCoordinates<>(date,
264 new FieldPVCoordinates<>(origin, FieldVector3D.getZero(date.getField())));
265 return bodyToInert.transformPVCoordinates(zeroPV);
266 }
267
268 @Override
269 public FieldVector3D<Gradient> getPosition(final FieldAbsoluteDate<Gradient> date, final Frame frame) {
270
271 final FieldVector3D<Gradient> origin = getOrigin(date, parameterIndices);
272
273
274 final KinematicTransform bodyToInertNonField = baseFrame.getParent().getKinematicTransformTo(frame,
275 date.toAbsoluteDate());
276 final FieldStaticTransform<Gradient> bodyToInert = shiftKinematicTransform(bodyToInertNonField,
277 date.durationFrom(date.toAbsoluteDate()));
278
279
280 return bodyToInert.getRotation().applyTo(bodyToInert.getTranslation().add(origin));
281 }
282 };
283 }
284
285
286
287
288
289
290
291 protected FieldVector3D<Gradient> getOrigin(final FieldAbsoluteDate<Gradient> date,
292 final Map<String, Integer> indices) {
293
294 final int freeParameters = date.getField().getZero().getFreeParameters();
295 final AbsoluteDate absoluteDate = date.toAbsoluteDate();
296 final Gradient x = eastOffsetDriver.getValue(freeParameters, indices, absoluteDate);
297 final Gradient y = northOffsetDriver.getValue(freeParameters, indices, absoluteDate);
298 final Gradient z = zenithOffsetDriver.getValue(freeParameters, indices, absoluteDate);
299 final FieldVector3D<Gradient> position = new FieldVector3D<>(x, y, z);
300
301 final Frame bodyFrame = baseFrame.getParentShape().getBodyFrame();
302 final KinematicTransform kinematicTopoToBody = baseFrame.getKinematicTransformTo(bodyFrame, absoluteDate);
303 final FieldStaticTransform<Gradient> staticTopoToBody = shiftKinematicTransform(kinematicTopoToBody,
304 date.durationFrom(absoluteDate));
305
306 final FieldVector3D<Gradient> originBeforeDisplacement = staticTopoToBody.transformPosition(position);
307 return originBeforeDisplacement.add(computeDisplacement(absoluteDate, originBeforeDisplacement.toVector3D()));
308 }
309
310
311
312
313
314
315
316
317 protected FieldStaticTransform<Gradient> shiftKinematicTransform(final KinematicTransform kinematicTransform,
318 final Gradient dt) {
319
320 final Field<Gradient> field = dt.getField();
321 final AbsoluteDate date = kinematicTransform.getDate();
322 final FieldVector3D<Gradient> fieldVelocity = new FieldVector3D<>(field, kinematicTransform.getVelocity());
323 final FieldVector3D<Gradient> shiftedTranslation = fieldVelocity.scalarMultiply(dt).add(kinematicTransform.getTranslation());
324
325 final FieldAngularCoordinates<Gradient> fieldAngularCoordinates = new FieldAngularCoordinates<>(field,
326 new AngularCoordinates(kinematicTransform.getRotation(), kinematicTransform.getRotationRate()));
327 final FieldVector3D<Gradient> rotationRate = fieldAngularCoordinates.getRotationRate();
328 final Gradient rate = rotationRate.getNorm();
329 final FieldRotation<Gradient> shiftedRotation = (rate.getReal() == 0.0) ?
330 fieldAngularCoordinates.getRotation() :
331 new FieldRotation<>(rotationRate, rate.multiply(dt), RotationConvention.FRAME_TRANSFORM)
332 .compose(fieldAngularCoordinates.getRotation(), RotationConvention.VECTOR_OPERATOR);
333 return FieldStaticTransform.of(new FieldAbsoluteDate<>(field, date).shiftedBy(dt), shiftedTranslation,
334 shiftedRotation);
335 }
336
337
338 @Override
339 public Transform getOffsetToInertial(final Frame inertial, final AbsoluteDate date,
340 final boolean clockOffsetAlreadyApplied) {
341
342
343 final AbsoluteDate offsetCompensatedDate = clockOffsetAlreadyApplied ?
344 date :
345 new AbsoluteDate(date, -getOffsetValue(date));
346
347 final TopocentricFrame topocentricFrame = (TopocentricFrame) getPVCoordinatesProvider();
348 return topocentricFrame.getTransformTo(inertial, offsetCompensatedDate);
349 }
350
351
352 @Override
353 public FieldTransform<Gradient> getOffsetToInertial(final Frame inertial,
354 final FieldAbsoluteDate<Gradient> offsetCompensatedDate,
355 final int freeParameters,
356 final Map<String, Integer> indices) {
357
358 final FieldVector3D<Gradient> origin = getOrigin(offsetCompensatedDate, indices);
359 final FieldGeodeticPoint<Gradient> originGP = baseFrame.getParentShape().transform(origin, baseFrame.getParent(),
360 offsetCompensatedDate);
361 final FieldStaticTransform<Gradient> staticOffsetToBody = TopocentricTransformProvider.getTransform(baseFrame.getParentShape(),
362 offsetCompensatedDate, originGP).getStaticInverse();
363 final FieldTransform<Gradient> offsetToBody = new FieldTransform<>(offsetCompensatedDate,
364 staticOffsetToBody.getTranslation(), staticOffsetToBody.getRotation());
365
366
367 final FieldTransform<Gradient> bodyToInert = baseFrame.getParent().getTransformTo(inertial, offsetCompensatedDate);
368
369
370 return new FieldTransform<>(offsetCompensatedDate, offsetToBody, bodyToInert);
371 }
372
373 }