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