Commit e44a76de authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Merge branch 'measurements-clock-offset' into develop

parents 6d60e87f f91722fb
......@@ -76,6 +76,7 @@ public class AngularAzEl extends AbstractMeasurement<AngularAzEl> {
final double[] angular, final double[] sigma, final double[] baseWeight,
final int propagatorIndex) {
super(date, angular, sigma, baseWeight, Arrays.asList(propagatorIndex),
station.getClockOffsetDriver(),
station.getEastOffsetDriver(),
station.getNorthOffsetDriver(),
station.getZenithOffsetDriver(),
......@@ -109,7 +110,7 @@ public class AngularAzEl extends AbstractMeasurement<AngularAzEl> {
// Parameters:
// - 0..2 - Position of the spacecraft in inertial frame
// - 3..5 - Velocity of the spacecraft in inertial frame
// - 6..n - station parameters (station offsets, pole, prime meridian...)
// - 6..n - station parameters (clock offset, station offsets, pole, prime meridian...)
// Get the number of parameters used for derivation
// Place the selected drivers into a map
......@@ -129,11 +130,10 @@ public class AngularAzEl extends AbstractMeasurement<AngularAzEl> {
// Transform between station and inertial frame, expressed as a derivative structure
// The components of station's position in offset frame are the 3 last derivative parameters
final AbsoluteDate downlinkDate = getDate();
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS =
new FieldAbsoluteDate<>(field, downlinkDate);
final FieldTransform<DerivativeStructure> offsetToInertialDownlink =
station.getOffsetToInertial(state.getFrame(), downlinkDateDS, factory, indices);
station.getOffsetToInertial(state.getFrame(), getDate(), factory, indices);
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS =
offsetToInertialDownlink.getFieldDate();
// Station position/velocity in inertial frame at end of the downlink leg
final TimeStampedFieldPVCoordinates<DerivativeStructure> stationDownlink =
......@@ -152,7 +152,7 @@ public class AngularAzEl extends AbstractMeasurement<AngularAzEl> {
final DerivativeStructure tauD = signalTimeOfFlight(pvaDS, stationDownlink.getPosition(), downlinkDateDS);
// Transit state
final double delta = downlinkDate.durationFrom(state.getDate());
final DerivativeStructure delta = downlinkDateDS.durationFrom(state.getDate());
final DerivativeStructure deltaMTauD = tauD.negate().add(delta);
final SpacecraftState transitState = state.shiftedBy(deltaMTauD.getValue());
......
......@@ -83,6 +83,7 @@ public class AngularRaDec extends AbstractMeasurement<AngularRaDec> {
final double[] angular, final double[] sigma, final double[] baseWeight,
final int propagatorIndex) {
super(date, angular, sigma, baseWeight, Arrays.asList(propagatorIndex),
station.getClockOffsetDriver(),
station.getEastOffsetDriver(),
station.getNorthOffsetDriver(),
station.getZenithOffsetDriver(),
......@@ -124,7 +125,7 @@ public class AngularRaDec extends AbstractMeasurement<AngularRaDec> {
// Parameters:
// - 0..2 - Position of the spacecraft in inertial frame
// - 3..5 - Velocity of the spacecraft in inertial frame
// - 6..n - station parameters (station offsets, pole, prime meridian...)
// - 6..n - station parameters (clock offset, station offsets, pole, prime meridian...)
// Get the number of parameters used for derivation
// Place the selected drivers into a map
......@@ -144,11 +145,10 @@ public class AngularRaDec extends AbstractMeasurement<AngularRaDec> {
// Transform between station and inertial frame, expressed as a derivative structure
// The components of station's position in offset frame are the 3 last derivative parameters
final AbsoluteDate downlinkDate = getDate();
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS =
new FieldAbsoluteDate<>(field, downlinkDate);
final FieldTransform<DerivativeStructure> offsetToInertialDownlink =
station.getOffsetToInertial(state.getFrame(), downlinkDateDS, factory, indices);
station.getOffsetToInertial(state.getFrame(), getDate(), factory, indices);
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS =
offsetToInertialDownlink.getFieldDate();
// Station position/velocity in inertial frame at end of the downlink leg
final TimeStampedFieldPVCoordinates<DerivativeStructure> stationDownlink =
......@@ -163,7 +163,7 @@ public class AngularRaDec extends AbstractMeasurement<AngularRaDec> {
final DerivativeStructure tauD = signalTimeOfFlight(pvaDS, stationDownlink.getPosition(), downlinkDateDS);
// Transit state
final double delta = downlinkDate.durationFrom(state.getDate());
final DerivativeStructure delta = downlinkDateDS.durationFrom(state.getDate());
final DerivativeStructure deltaMTauD = tauD.negate().add(delta);
final SpacecraftState transitState = state.shiftedBy(deltaMTauD.getValue());
......
......@@ -64,6 +64,11 @@ import org.orekit.utils.ParameterDriver;
* station frame (for non-Earth based ground stations, different precession nutation
* models and associated planet oritentation parameters would be applied, if available):
* </p>
* <p>
* Since 9.3, this class also adds a station clock offset parameter, which manages
* the value that must be added to the observed measurement date to get the real
* physical date at which the measurement was performed.
* </p>
* <ol>
* <li>precession/nutation, as theoretical model plus celestial pole EOP parameters</li>
* <li>body rotation, as theoretical model plus prime meridian EOP parameters</li>
......@@ -71,6 +76,7 @@ import org.orekit.utils.ParameterDriver;
* <li>additional body rotation, controlled by {@link #getPrimeMeridianOffsetDriver()} and {@link #getPrimeMeridianDriftDriver()}</li>
* <li>additional polar motion, controlled by {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()},
* {@link #getPolarOffsetYDriver()} and {@link #getPolarDriftYDriver()}</li>
* <li>station clock offset, controlled by {@link #getClockOffsetDriver()}</li>
* <li>station position offset, controlled by {@link #getEastOffsetDriver()},
* {@link #getNorthOffsetDriver()} and {@link #getZenithOffsetDriver()}</li>
* </ol>
......@@ -79,19 +85,27 @@ import org.orekit.utils.ParameterDriver;
*/
public class GroundStation {
/** Suffix for ground station position offset parameter name. */
/** Suffix for ground station position and clock offset parameters names. */
public static final String OFFSET_SUFFIX = "-offset";
/** Suffix for ground station intermediate frame name. */
public static final String INTERMEDIATE_SUFFIX = "-intermediate";
/** Offsets scaling factor.
/** Clock offset scaling factor.
* <p>
* We use a power of 2 to avoid numeric noise introduction
* in the multiplications/divisions sequences.
* </p>
*/
private static final double CLOCK_OFFSET_SCALE = FastMath.scalb(1.0, -10);
/** Position offsets scaling factor.
* <p>
* We use a power of 2 (in fact really 1.0 here) to avoid numeric noise introduction
* in the multiplications/divisions sequences.
* </p>
*/
private static final double OFFSET_SCALE = FastMath.scalb(1.0, 0);
private static final double POSITION_OFFSET_SCALE = FastMath.scalb(1.0, 0);
/** Provider for Earth frame whose EOP parameters can be estimated. */
private final EstimatedEarthFrameProvider estimatedEarthFrameProvider;
......@@ -108,6 +122,9 @@ public class GroundStation {
/** Displacement models. */
private final StationDisplacement[] displacements;
/** Driver for clock offset. */
private final ParameterDriver clockOffsetDriver;
/** Driver for position offset along the East axis. */
private final ParameterDriver eastOffsetDriver;
......@@ -123,8 +140,9 @@ public class GroundStation {
* ({@link #getPrimeMeridianOffsetDriver()}, {@link #getPrimeMeridianDriftDriver()},
* {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()},
* {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()}) are set to 0.
* The initial values for the station offset model ({@link #getEastOffsetDriver()},
* {@link #getNorthOffsetDriver()}, {@link #getZenithOffsetDriver()}) are set to 0.
* The initial values for the station offset model ({@link #getClockOffsetDriver()},
* {@link #getEastOffsetDriver()}, {@link #getNorthOffsetDriver()},
* {@link #getZenithOffsetDriver()}) are set to 0.
* This implies that as long as these values are not changed, the offset frame is
* the same as the {@link #getBaseFrame() base frame}. As soon as some of these models
* are changed, the offset frame moves away from the {@link #getBaseFrame() base frame}.
......@@ -143,8 +161,9 @@ public class GroundStation {
* ({@link #getPrimeMeridianOffsetDriver()}, {@link #getPrimeMeridianDriftDriver()},
* {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()},
* {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()}) are set to 0.
* The initial values for the station offset model ({@link #getEastOffsetDriver()},
* {@link #getNorthOffsetDriver()}, {@link #getZenithOffsetDriver()}) are set to 0.
* The initial values for the station offset model ({@link #getClockOffsetDriver()},
* {@link #getEastOffsetDriver()}, {@link #getNorthOffsetDriver()},
* {@link #getZenithOffsetDriver()}, {@link #getClockOffsetDriver()}) are set to 0.
* This implies that as long as these values are not changed, the offset frame is
* the same as the {@link #getBaseFrame() base frame}. As soon as some of these models
* are changed, the offset frame moves away from the {@link #getBaseFrame() base frame}.
......@@ -178,16 +197,20 @@ public class GroundStation {
this.displacements = displacements.clone();
this.clockOffsetDriver = new ParameterDriver(baseFrame.getName() + OFFSET_SUFFIX + "-clock",
0.0, CLOCK_OFFSET_SCALE,
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
this.eastOffsetDriver = new ParameterDriver(baseFrame.getName() + OFFSET_SUFFIX + "-East",
0.0, OFFSET_SCALE,
0.0, POSITION_OFFSET_SCALE,
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
this.northOffsetDriver = new ParameterDriver(baseFrame.getName() + OFFSET_SUFFIX + "-North",
0.0, OFFSET_SCALE,
0.0, POSITION_OFFSET_SCALE,
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
this.zenithOffsetDriver = new ParameterDriver(baseFrame.getName() + OFFSET_SUFFIX + "-Zenith",
0.0, OFFSET_SCALE,
0.0, POSITION_OFFSET_SCALE,
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
......@@ -200,6 +223,14 @@ public class GroundStation {
return displacements.clone();
}
/** Get a driver allowing to change station clock (which is related to measurement date).
* @return driver for station clock offset
* @since 9.3
*/
public ParameterDriver getClockOffsetDriver() {
return clockOffsetDriver;
}
/** Get a driver allowing to change station position along East axis.
* @return driver for station position offset along East axis
*/
......@@ -390,68 +421,102 @@ public class GroundStation {
* a new offset frame.
* </p>
* @param inertial inertial frame to transform to
* @param date date of the transform
* @return offset frame defining vectors
* @param clockDate date of the transform as read by the ground station clock (i.e. clock offset <em>not</em> compensated)
* @return transform between offset frame and inertial frame, at <em>real</em> measurement
* date (i.e. with clock, Earth and station offsets applied)
*/
public Transform getOffsetToInertial(final Frame inertial, final AbsoluteDate date) {
public Transform getOffsetToInertial(final Frame inertial, final AbsoluteDate clockDate) {
// take clock offset into account
final double offset = parametricModel(clockOffsetDriver);
final AbsoluteDate offsetCompensatedDate = new AbsoluteDate(clockDate, offset);
// take Earth offsets into account
final Transform intermediateToBody = estimatedEarthFrameProvider.getTransform(date).getInverse();
final Transform intermediateToBody = estimatedEarthFrameProvider.getTransform(offsetCompensatedDate).getInverse();
// take station offset into account
// take station offsets into account
final double x = parametricModel(eastOffsetDriver);
final double y = parametricModel(northOffsetDriver);
final double z = parametricModel(zenithOffsetDriver);
final BodyShape baseShape = baseFrame.getParentShape();
final Transform baseToBody = baseFrame.getTransformTo(baseShape.getBodyFrame(), date);
final Transform baseToBody = baseFrame.getTransformTo(baseShape.getBodyFrame(), offsetCompensatedDate);
Vector3D origin = baseToBody.transformPosition(new Vector3D(x, y, z));
origin = origin.add(computeDisplacement(date, origin));
origin = origin.add(computeDisplacement(offsetCompensatedDate, origin));
final GeodeticPoint originGP = baseShape.transform(origin, baseShape.getBodyFrame(), date);
final GeodeticPoint originGP = baseShape.transform(origin, baseShape.getBodyFrame(), offsetCompensatedDate);
final Transform offsetToIntermediate =
new Transform(date,
new Transform(date,
new Transform(offsetCompensatedDate,
new Transform(offsetCompensatedDate,
new Rotation(Vector3D.PLUS_I, Vector3D.PLUS_K,
originGP.getEast(), originGP.getZenith()),
Vector3D.ZERO),
new Transform(date, origin));
new Transform(offsetCompensatedDate, origin));
// combine all transforms together
final Transform bodyToInert = baseFrame.getParent().getTransformTo(inertial, date);
final Transform bodyToInert = baseFrame.getParent().getTransformTo(inertial, offsetCompensatedDate);
return new Transform(date, offsetToIntermediate, new Transform(date, intermediateToBody, bodyToInert));
return new Transform(offsetCompensatedDate, offsetToIntermediate, new Transform(offsetCompensatedDate, intermediateToBody, bodyToInert));
}
/** Get the transform between offset frame and inertial frame with derivatives.
* <p>
* As the East and North vector are not well defined at pole, the derivatives
* As the East and North vectors are not well defined at pole, the derivatives
* of these two vectors diverge to infinity as we get closer to the pole.
* So this method should not be used for stations less than 0.0001 degree from
* either poles.
* </p>
* @param inertial inertial frame to transform to
* @param date date of the transform
* @param clockDate date of the transform as read by the ground station clock (i.e. clock offset <em>not</em> compensated)
* @param factory factory for the derivatives
* @param indices indices of the estimated parameters in derivatives computations
* @return offset frame defining vectors with derivatives
* @return transform between offset frame and inertial frame, at <em>real</em> measurement
* date (i.e. with clock, Earth and station offsets applied)
* @see #getOffsetToInertial(Frame, FieldAbsoluteDate, DSFactory, Map)
* @since 9.3
*/
public FieldTransform<DerivativeStructure> getOffsetToInertial(final Frame inertial,
final AbsoluteDate clockDate,
final DSFactory factory,
final Map<String, Integer> indices) {
// take clock offset into account
final DerivativeStructure offset = parametricModel(factory, clockOffsetDriver, indices);
final FieldAbsoluteDate<DerivativeStructure> offsetCompensatedDate =
new FieldAbsoluteDate<DerivativeStructure>(clockDate, offset);
return getOffsetToInertial(inertial, offsetCompensatedDate, factory, indices);
}
/** Get the transform between offset frame and inertial frame with derivatives.
* <p>
* As the East and North vectors are not well defined at pole, the derivatives
* of these two vectors diverge to infinity as we get closer to the pole.
* So this method should not be used for stations less than 0.0001 degree from
* either poles.
* </p>
* @param inertial inertial frame to transform to
* @param offsetCompensatedDate date of the transform, clock offset and its derivatives already compensated
* @param factory factory for the derivatives
* @param indices indices of the estimated parameters in derivatives computations
* @return transform between offset frame and inertial frame, at specified date
* @see #getOffsetToInertial(Frame, AbsoluteDate, DSFactory, Map)
* @since 9.0
*/
public FieldTransform<DerivativeStructure> getOffsetToInertial(final Frame inertial,
final FieldAbsoluteDate<DerivativeStructure> date,
final FieldAbsoluteDate<DerivativeStructure> offsetCompensatedDate,
final DSFactory factory,
final Map<String, Integer> indices) {
final Field<DerivativeStructure> field = date.getField();
final Field<DerivativeStructure> field = factory.getDerivativeField();
final FieldVector3D<DerivativeStructure> zero = FieldVector3D.getZero(field);
final FieldVector3D<DerivativeStructure> plusI = FieldVector3D.getPlusI(field);
final FieldVector3D<DerivativeStructure> plusK = FieldVector3D.getPlusK(field);
// take Earth offsets into account
final FieldTransform<DerivativeStructure> intermediateToBody =
estimatedEarthFrameProvider.getTransform(date, factory, indices).getInverse();
estimatedEarthFrameProvider.getTransform(offsetCompensatedDate, factory, indices).getInverse();
// take station offset into account
// take station offsets into account
final DerivativeStructure x = parametricModel(factory, eastOffsetDriver, indices);
final DerivativeStructure y = parametricModel(factory, northOffsetDriver, indices);
final DerivativeStructure z = parametricModel(factory, zenithOffsetDriver, indices);
......@@ -459,22 +524,22 @@ public class GroundStation {
final Transform baseToBody = baseFrame.getTransformTo(baseShape.getBodyFrame(), (AbsoluteDate) null);
FieldVector3D<DerivativeStructure> origin = baseToBody.transformPosition(new FieldVector3D<>(x, y, z));
origin = origin.add(computeDisplacement(date.toAbsoluteDate(), origin.toVector3D()));
final FieldGeodeticPoint<DerivativeStructure> originGP = baseShape.transform(origin, baseShape.getBodyFrame(), date);
origin = origin.add(computeDisplacement(offsetCompensatedDate.toAbsoluteDate(), origin.toVector3D()));
final FieldGeodeticPoint<DerivativeStructure> originGP = baseShape.transform(origin, baseShape.getBodyFrame(), offsetCompensatedDate);
final FieldTransform<DerivativeStructure> offsetToIntermediate =
new FieldTransform<>(date,
new FieldTransform<>(date,
new FieldTransform<>(offsetCompensatedDate,
new FieldTransform<>(offsetCompensatedDate,
new FieldRotation<>(plusI, plusK,
originGP.getEast(), originGP.getZenith()),
zero),
new FieldTransform<>(date, origin));
new FieldTransform<>(offsetCompensatedDate, origin));
// combine all transforms together
final FieldTransform<DerivativeStructure> bodyToInert = baseFrame.getParent().getTransformTo(inertial, date);
final FieldTransform<DerivativeStructure> bodyToInert = baseFrame.getParent().getTransformTo(inertial, offsetCompensatedDate);
return new FieldTransform<>(date,
return new FieldTransform<>(offsetCompensatedDate,
offsetToIntermediate,
new FieldTransform<>(date, intermediateToBody, bodyToInert));
new FieldTransform<>(offsetCompensatedDate, intermediateToBody, bodyToInert));
}
......
......@@ -88,6 +88,7 @@ public class Phase extends AbstractMeasurement<Phase> {
final double phase, final double wavelength, final double sigma,
final double baseWeight, final int propagatorIndex) {
super(date, phase, sigma, baseWeight, Arrays.asList(propagatorIndex),
station.getClockOffsetDriver(),
station.getEastOffsetDriver(),
station.getNorthOffsetDriver(),
station.getZenithOffsetDriver(),
......@@ -123,7 +124,7 @@ public class Phase extends AbstractMeasurement<Phase> {
// Parameters:
// - 0..2 - Position of the spacecraft in inertial frame
// - 3..5 - Velocity of the spacecraft in inertial frame
// - 6..n - station parameters (station offsets, pole, prime meridian...)
// - 6..n - station parameters (clock offset, station offsets, pole, prime meridian...)
int nbParams = 6;
final Map<String, Integer> indices = new HashMap<>();
for (ParameterDriver driver : getParametersDrivers()) {
......@@ -140,11 +141,10 @@ public class Phase extends AbstractMeasurement<Phase> {
// transform between station and inertial frame, expressed as a derivative structure
// The components of station's position in offset frame are the 3 last derivative parameters
final AbsoluteDate downlinkDate = getDate();
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS =
new FieldAbsoluteDate<>(field, downlinkDate);
final FieldTransform<DerivativeStructure> offsetToInertialDownlink =
station.getOffsetToInertial(state.getFrame(), downlinkDateDS, factory, indices);
station.getOffsetToInertial(state.getFrame(), getDate(), factory, indices);
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS =
offsetToInertialDownlink.getFieldDate();
// Station position in inertial frame at end of the downlink leg
final TimeStampedFieldPVCoordinates<DerivativeStructure> stationDownlink =
......@@ -159,7 +159,7 @@ public class Phase extends AbstractMeasurement<Phase> {
final DerivativeStructure tauD = signalTimeOfFlight(pvaDS, stationDownlink.getPosition(), downlinkDateDS);
// Transit state & Transit state (re)computed with derivative structures
final double delta = downlinkDate.durationFrom(state.getDate());
final DerivativeStructure delta = downlinkDateDS.durationFrom(state.getDate());
final DerivativeStructure deltaMTauD = tauD.negate().add(delta);
final SpacecraftState transitState = state.shiftedBy(deltaMTauD.getValue());
final TimeStampedFieldPVCoordinates<DerivativeStructure> transitStateDS = pvaDS.shiftedBy(deltaMTauD);
......
......@@ -131,6 +131,7 @@ public class Range extends AbstractMeasurement<Range> {
final double range, final double sigma, final double baseWeight,
final int propagatorIndex) {
super(date, range, sigma, baseWeight, Arrays.asList(propagatorIndex),
station.getClockOffsetDriver(),
station.getEastOffsetDriver(),
station.getNorthOffsetDriver(),
station.getZenithOffsetDriver(),
......@@ -173,7 +174,7 @@ public class Range extends AbstractMeasurement<Range> {
// Parameters:
// - 0..2 - Position of the spacecraft in inertial frame
// - 3..5 - Velocity of the spacecraft in inertial frame
// - 6..n - station parameters (station offsets, pole, prime meridian...)
// - 6..n - measurements parameters (clock offset, station offsets, pole, prime meridian...)
int nbParams = 6;
final Map<String, Integer> indices = new HashMap<>();
for (ParameterDriver driver : getParametersDrivers()) {
......@@ -190,11 +191,9 @@ public class Range extends AbstractMeasurement<Range> {
// transform between station and inertial frame, expressed as a derivative structure
// The components of station's position in offset frame are the 3 last derivative parameters
final AbsoluteDate downlinkDate = getDate();
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS =
new FieldAbsoluteDate<>(field, downlinkDate);
final FieldTransform<DerivativeStructure> offsetToInertialDownlink =
station.getOffsetToInertial(state.getFrame(), downlinkDateDS, factory, indices);
station.getOffsetToInertial(state.getFrame(), getDate(), factory, indices);
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS = offsetToInertialDownlink.getFieldDate();
// Station position in inertial frame at end of the downlink leg
final TimeStampedFieldPVCoordinates<DerivativeStructure> stationDownlink =
......@@ -209,7 +208,7 @@ public class Range extends AbstractMeasurement<Range> {
final DerivativeStructure tauD = signalTimeOfFlight(pvaDS, stationDownlink.getPosition(), downlinkDateDS);
// Transit state & Transit state (re)computed with derivative structures
final double delta = downlinkDate.durationFrom(state.getDate());
final DerivativeStructure delta = downlinkDateDS.durationFrom(state.getDate());
final DerivativeStructure deltaMTauD = tauD.negate().add(delta);
final SpacecraftState transitState = state.shiftedBy(deltaMTauD.getValue());
final TimeStampedFieldPVCoordinates<DerivativeStructure> transitStateDS = pvaDS.shiftedBy(deltaMTauD);
......
......@@ -92,6 +92,7 @@ public class RangeRate extends AbstractMeasurement<RangeRate> {
final boolean twoway,
final int propagatorIndex) {
super(date, rangeRate, sigma, baseWeight, Arrays.asList(propagatorIndex),
station.getClockOffsetDriver(),
station.getEastOffsetDriver(),
station.getNorthOffsetDriver(),
station.getZenithOffsetDriver(),
......@@ -133,7 +134,7 @@ public class RangeRate extends AbstractMeasurement<RangeRate> {
// Parameters:
// - 0..2 - Position of the spacecraft in inertial frame
// - 3..5 - Velocity of the spacecraft in inertial frame
// - 6..n - station parameters (station offsets, pole, prime meridian...)
// - 6..n - station parameters (clock offset, station offsets, pole, prime meridian...)
int nbParams = 6;
final Map<String, Integer> indices = new HashMap<>();
for (ParameterDriver driver : getParametersDrivers()) {
......@@ -150,11 +151,10 @@ public class RangeRate extends AbstractMeasurement<RangeRate> {
// transform between station and inertial frame, expressed as a derivative structure
// The components of station's position in offset frame are the 3 last derivative parameters
final AbsoluteDate downlinkDate = getDate();
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS =
new FieldAbsoluteDate<>(field, downlinkDate);
final FieldTransform<DerivativeStructure> offsetToInertialDownlink =
station.getOffsetToInertial(state.getFrame(), downlinkDateDS, factory, indices);
station.getOffsetToInertial(state.getFrame(), getDate(), factory, indices);
final FieldAbsoluteDate<DerivativeStructure> downlinkDateDS =
offsetToInertialDownlink.getFieldDate();
// Station position in inertial frame at end of the downlink leg
final TimeStampedFieldPVCoordinates<DerivativeStructure> stationDownlink =
......@@ -169,7 +169,7 @@ public class RangeRate extends AbstractMeasurement<RangeRate> {
final DerivativeStructure tauD = signalTimeOfFlight(pvaDS, stationDownlink.getPosition(), downlinkDateDS);
// Transit state
final double delta = downlinkDate.durationFrom(state.getDate());
final DerivativeStructure delta = downlinkDateDS.durationFrom(state.getDate());
final DerivativeStructure deltaMTauD = tauD.negate().add(delta);
final SpacecraftState transitState = state.shiftedBy(deltaMTauD.getValue());
......@@ -183,10 +183,11 @@ public class RangeRate extends AbstractMeasurement<RangeRate> {
final EstimatedMeasurement<RangeRate> estimated;
if (twoway) {
// one-way (uplink) light time correction
final AbsoluteDate approxUplinkDate = downlinkDate.shiftedBy(-2 * tauD.getValue());
final FieldAbsoluteDate<DerivativeStructure> approxUplinkDateDS = new FieldAbsoluteDate<>(field, approxUplinkDate);
final FieldTransform<DerivativeStructure> offsetToInertialApproxUplink =
station.getOffsetToInertial(state.getFrame(), approxUplinkDateDS, factory, indices);
station.getOffsetToInertial(state.getFrame(),
downlinkDateDS.shiftedBy(tauD.multiply(-2)), factory, indices);
final FieldAbsoluteDate<DerivativeStructure> approxUplinkDateDS =
offsetToInertialApproxUplink.getFieldDate();
final TimeStampedFieldPVCoordinates<DerivativeStructure> stationApproxUplink =
offsetToInertialApproxUplink.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(approxUplinkDateDS,
......
......@@ -98,6 +98,7 @@ public class TurnAroundRange extends AbstractMeasurement<TurnAroundRange> {
final double sigma, final double baseWeight,
final int propagatorIndex) {
super(date, turnAroundRange, sigma, baseWeight, Arrays.asList(propagatorIndex),
masterStation.getClockOffsetDriver(),
masterStation.getEastOffsetDriver(),
masterStation.getNorthOffsetDriver(),
masterStation.getZenithOffsetDriver(),
......@@ -107,6 +108,7 @@ public class TurnAroundRange extends AbstractMeasurement<TurnAroundRange> {
masterStation.getPolarDriftXDriver(),
masterStation.getPolarOffsetYDriver(),
masterStation.getPolarDriftYDriver(),
// the slave station clock is not used at all, we ignore the corresponding parameter driver
slaveStation.getEastOffsetDriver(),
slaveStation.getNorthOffsetDriver(),
slaveStation.getZenithOffsetDriver(),
......@@ -149,7 +151,7 @@ public class TurnAroundRange extends AbstractMeasurement<TurnAroundRange> {
//
// - 0..2 - Position of the spacecraft in inertial frame
// - 3..5 - Velocity of the spacecraft in inertial frame
// - 6..n - stations' parameters (stations' offsets, pole, prime meridian...)
// - 6..n - stations' parameters (clock offset, station offsets, pole, prime meridian...)
int nbParams = 6;
final Map<String, Integer> indices = new HashMap<>();
for (ParameterDriver driver : getParametersDrivers()) {
......@@ -188,18 +190,18 @@ public class TurnAroundRange extends AbstractMeasurement<TurnAroundRange> {
// Time difference between t (date of the measurement) and t' (date tagged in spacecraft state)
// (if state has already been set up to pre-compensate propagation delay,
// we will have delta = masterTauD + slaveTauU)
final AbsoluteDate measurementDate = getDate();
final FieldAbsoluteDate<DerivativeStructure> measurementDateDS = new FieldAbsoluteDate<>(field, measurementDate);
final double delta = measurementDate.durationFrom(state.getDate());
final double delta = getDate().durationFrom(state.getDate());
// transform between master station topocentric frame (east-north-zenith) and inertial frame expressed as DerivativeStructures
final FieldTransform<DerivativeStructure> masterToInert =
masterStation.getOffsetToInertial(state.getFrame(), measurementDateDS, factory, indices);
masterStation.getOffsetToInertial(state.getFrame(), getDate(), factory, indices);
final FieldAbsoluteDate<DerivativeStructure> measurementDateDS =
masterToInert.getFieldDate();
// Master station PV in inertial frame at measurement date
final TimeStampedFieldPVCoordinates<DerivativeStructure> masterArrival =
masterToInert.transformPVCoordinates(new TimeStampedPVCoordinates(measurementDate,
PVCoordinates.ZERO));
masterToInert.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(measurementDateDS,
zero, zero, zero));
// Compute propagation times
final DerivativeStructure masterTauD = signalTimeOfFlight(pvaDS, masterArrival.getPosition(), measurementDateDS);
......
......@@ -178,7 +178,8 @@ public class RangeIonosphericDelayModifier implements EstimationModifier<Range>
}
estimated.setStateDerivatives(0, stateDerivatives);
for (final ParameterDriver driver : Arrays.asList(station.getEastOffsetDriver(),
for (final ParameterDriver driver : Arrays.asList(station.getClockOffsetDriver(),
station.getEastOffsetDriver(),
station.getNorthOffsetDriver(),
station.getZenithOffsetDriver())) {
if (driver.isSelected()) {
......
......@@ -216,7 +216,8 @@ public class RangeRateIonosphericDelayModifier implements EstimationModifier<Ran
}
estimated.setStateDerivatives(0, stateDerivatives);
for (final ParameterDriver driver : Arrays.asList(station.getEastOffsetDriver(),
for (final ParameterDriver driver : Arrays.asList(station.getClockOffsetDriver(),
station.getEastOffsetDriver(),
station.getNorthOffsetDriver(),
station.getZenithOffsetDriver())) {
if (driver.isSelected()) {
......