Commit b1fcb60b authored by Luc Maisonobe's avatar Luc Maisonobe

Take clock offsets into account in range (ground or sat based).

Fixes #515
parent 735d5e4b
......@@ -122,7 +122,8 @@ public class AngularAzEl extends AbstractMeasurement<AngularAzEl> {
protected EstimatedMeasurement<AngularAzEl> theoreticalEvaluation(final int iteration, final int evaluation,
final SpacecraftState[] states) {
final SpacecraftState state = states[getPropagatorsIndices().get(0)];
final ObservableSatellite satellite = getSatellites().get(0);
final SpacecraftState state = states[satellite.getPropagatorIndex()];
// Azimuth/elevation derivatives are computed with respect to spacecraft state in inertial frame
// and station parameters
......
......@@ -139,7 +139,8 @@ public class AngularRaDec extends AbstractMeasurement<AngularRaDec> {
protected EstimatedMeasurement<AngularRaDec> theoreticalEvaluation(final int iteration, final int evaluation,
final SpacecraftState[] states) {
final SpacecraftState state = states[getPropagatorsIndices().get(0)];
final ObservableSatellite satellite = getSatellites().get(0);
final SpacecraftState state = states[satellite.getPropagatorIndex()];
// Right Ascension/elevation (in reference frame )derivatives are computed with respect to spacecraft state in inertial frame
// and station parameters
......
......@@ -219,7 +219,7 @@ public class EstimatedEarthFrameProvider implements TransformProvider {
// take parametric prime meridian shift into account
final double theta = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver);
final double thetaDot = parametricModel(primeMeridianDriftDriver);
final double thetaDot = primeMeridianDriftDriver.getValue();
final Transform meridianShift =
new Transform(date,
new Rotation(Vector3D.PLUS_K, theta, RotationConvention.FRAME_TRANSFORM),
......@@ -228,8 +228,8 @@ public class EstimatedEarthFrameProvider implements TransformProvider {
// take parametric pole shift into account
final double xpNeg = -linearModel(date, polarOffsetXDriver, polarDriftXDriver);
final double ypNeg = -linearModel(date, polarOffsetYDriver, polarDriftYDriver);
final double xpNegDot = -parametricModel(polarDriftXDriver);
final double ypNegDot = -parametricModel(polarDriftYDriver);
final double xpNegDot = -polarDriftXDriver.getValue();
final double ypNegDot = -polarDriftYDriver.getValue();
final Transform poleShift =
new Transform(date,
new Transform(date,
......@@ -251,13 +251,13 @@ public class EstimatedEarthFrameProvider implements TransformProvider {
// prime meridian shift parameters
final T theta = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver);
final T thetaDot = zero.add(parametricModel(primeMeridianDriftDriver));
final T thetaDot = zero.add(primeMeridianDriftDriver.getValue());
// pole shift parameters
final T xpNeg = linearModel(date, polarOffsetXDriver, polarDriftXDriver).negate();
final T ypNeg = linearModel(date, polarOffsetYDriver, polarDriftYDriver).negate();
final T xpNegDot = zero.subtract(parametricModel(polarDriftXDriver));
final T ypNegDot = zero.subtract(parametricModel(polarDriftYDriver));
final T xpNegDot = zero.subtract(polarDriftXDriver.getValue());
final T ypNegDot = zero.subtract(polarDriftYDriver.getValue());
return getTransform(date, theta, thetaDot, xpNeg, xpNegDot, ypNeg, ypNegDot);
......@@ -277,15 +277,15 @@ public class EstimatedEarthFrameProvider implements TransformProvider {
final DerivativeStructure theta = linearModel(factory, date,
primeMeridianOffsetDriver, primeMeridianDriftDriver,
indices);
final DerivativeStructure thetaDot = parametricModel(factory, primeMeridianDriftDriver, indices);
final DerivativeStructure thetaDot = primeMeridianDriftDriver.getValue(factory, indices);
// pole shift parameters
final DerivativeStructure xpNeg = linearModel(factory, date,
polarOffsetXDriver, polarDriftXDriver, indices).negate();
final DerivativeStructure ypNeg = linearModel(factory, date,
polarOffsetYDriver, polarDriftYDriver, indices).negate();
final DerivativeStructure xpNegDot = parametricModel(factory, polarDriftXDriver, indices).negate();
final DerivativeStructure ypNegDot = parametricModel(factory, polarDriftYDriver, indices).negate();
final DerivativeStructure xpNegDot = polarDriftXDriver.getValue(factory, indices).negate();
final DerivativeStructure ypNegDot = polarDriftYDriver.getValue(factory, indices).negate();
return getTransform(date, theta, thetaDot, xpNeg, xpNegDot, ypNeg, ypNegDot);
......@@ -345,8 +345,8 @@ public class EstimatedEarthFrameProvider implements TransformProvider {
offsetDriver.getName());
}
final double dt = date.durationFrom(offsetDriver.getReferenceDate());
final double offset = parametricModel(offsetDriver);
final double drift = parametricModel(driftDriver);
final double offset = offsetDriver.getValue();
final double drift = driftDriver.getValue();
return dt * drift + offset;
}
......@@ -365,8 +365,8 @@ public class EstimatedEarthFrameProvider implements TransformProvider {
offsetDriver.getName());
}
final T dt = date.durationFrom(offsetDriver.getReferenceDate());
final double offset = parametricModel(offsetDriver);
final double drift = parametricModel(driftDriver);
final double offset = offsetDriver.getValue();
final double drift = driftDriver.getValue();
return dt.multiply(drift).add(offset);
}
......@@ -386,33 +386,11 @@ public class EstimatedEarthFrameProvider implements TransformProvider {
offsetDriver.getName());
}
final DerivativeStructure dt = date.durationFrom(offsetDriver.getReferenceDate());
final DerivativeStructure offset = parametricModel(factory, offsetDriver, indices);
final DerivativeStructure drift = parametricModel(factory, driftDriver, indices);
final DerivativeStructure offset = offsetDriver.getValue(factory, indices);
final DerivativeStructure drift = driftDriver.getValue(factory, indices);
return dt.multiply(drift).add(offset);
}
/** Evaluate a parametric model.
* @param driver driver managing the parameter
* @return value of the parametric model
*/
private double parametricModel(final ParameterDriver driver) {
return driver.getValue();
}
/** Evaluate a parametric model.
* @param factory factory for the derivatives
* @param driver driver managing the parameter
* @param indices indices of the estimated parameters in derivatives computations
* @return value of the parametric model
*/
private DerivativeStructure parametricModel(final DSFactory factory, final ParameterDriver driver,
final Map<String, Integer> indices) {
final Integer index = indices.get(driver.getName());
return (index == null) ?
factory.constant(driver.getValue()) :
factory.variable(index, driver.getValue());
}
/** Replace the instance with a data transfer object for serialization.
* <p>
* This intermediate class serializes the files supported names, the ephemeris type
......
......@@ -66,8 +66,9 @@ import org.orekit.utils.ParameterDriver;
* </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.
* the value that must be subtracted from the observed measurement date to get the real
* physical date at which the measurement was performed (i.e. the offset is negative
* if the ground station clock is slow and positive if it is fast).
* </p>
* <ol>
* <li>precession/nutation, as theoretical model plus celestial pole EOP parameters</li>
......@@ -396,9 +397,9 @@ public class GroundStation {
public GeodeticPoint getOffsetGeodeticPoint(final AbsoluteDate date) {
// take station offset into account
final double x = parametricModel(eastOffsetDriver);
final double y = parametricModel(northOffsetDriver);
final double z = parametricModel(zenithOffsetDriver);
final double x = eastOffsetDriver.getValue();
final double y = northOffsetDriver.getValue();
final double z = zenithOffsetDriver.getValue();
final BodyShape baseShape = baseFrame.getParentShape();
final Transform baseToBody = baseFrame.getTransformTo(baseShape.getBodyFrame(), date);
Vector3D origin = baseToBody.transformPosition(new Vector3D(x, y, z));
......@@ -428,16 +429,16 @@ public class GroundStation {
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);
final double offset = clockOffsetDriver.getValue();
final AbsoluteDate offsetCompensatedDate = new AbsoluteDate(clockDate, -offset);
// take Earth offsets into account
final Transform intermediateToBody = estimatedEarthFrameProvider.getTransform(offsetCompensatedDate).getInverse();
// take station offsets into account
final double x = parametricModel(eastOffsetDriver);
final double y = parametricModel(northOffsetDriver);
final double z = parametricModel(zenithOffsetDriver);
final double x = eastOffsetDriver.getValue();
final double y = northOffsetDriver.getValue();
final double z = zenithOffsetDriver.getValue();
final BodyShape baseShape = baseFrame.getParentShape();
final Transform baseToBody = baseFrame.getTransformTo(baseShape.getBodyFrame(), offsetCompensatedDate);
Vector3D origin = baseToBody.transformPosition(new Vector3D(x, y, z));
......@@ -480,9 +481,9 @@ public class GroundStation {
final DSFactory factory,
final Map<String, Integer> indices) {
// take clock offset into account
final DerivativeStructure offset = parametricModel(factory, clockOffsetDriver, indices);
final DerivativeStructure offset = clockOffsetDriver.getValue(factory, indices);
final FieldAbsoluteDate<DerivativeStructure> offsetCompensatedDate =
new FieldAbsoluteDate<DerivativeStructure>(clockDate, offset);
new FieldAbsoluteDate<DerivativeStructure>(clockDate, offset.negate());
return getOffsetToInertial(inertial, offsetCompensatedDate, factory, indices);
}
......@@ -517,9 +518,9 @@ public class GroundStation {
estimatedEarthFrameProvider.getTransform(offsetCompensatedDate, factory, indices).getInverse();
// 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);
final DerivativeStructure x = eastOffsetDriver.getValue(factory, indices);
final DerivativeStructure y = northOffsetDriver.getValue(factory, indices);
final DerivativeStructure z = zenithOffsetDriver.getValue(factory, indices);
final BodyShape baseShape = baseFrame.getParentShape();
final Transform baseToBody = baseFrame.getTransformTo(baseShape.getBodyFrame(), (AbsoluteDate) null);
......@@ -543,26 +544,4 @@ public class GroundStation {
}
/** Evaluate a parametric model.
* @param driver driver managing the parameter
* @return value of the parametric model
*/
private double parametricModel(final ParameterDriver driver) {
return driver.getValue();
}
/** Evaluate a parametric model.
* @param factory factory for the derivatives
* @param driver driver managing the parameter
* @param indices indices of the estimated parameters in derivatives computations
* @return value of the parametric model
*/
private DerivativeStructure parametricModel(final DSFactory factory, final ParameterDriver driver,
final Map<String, Integer> indices) {
final Integer index = indices.get(driver.getName());
return (index == null) ?
factory.constant(driver.getValue()) :
factory.variable(index, driver.getValue());
}
}
......@@ -16,6 +16,9 @@
*/
package org.orekit.estimation.measurements;
import org.hipparchus.util.FastMath;
import org.orekit.utils.ParameterDriver;
/** Class modeling a satellite that can be observed.
*
* @author Luc Maisonobe
......@@ -23,14 +26,31 @@ package org.orekit.estimation.measurements;
*/
public class ObservableSatellite {
/** Prefix for clock offset parameter driver, the propagator index will be appended to it. */
public static final String CLOCK_OFFSET_PREFIX = "clock-offset-satellite-";
/** 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);
/** Index of the propagator related to this satellite. */
private final int propagatorIndex;
/** Parameter driver for satellite clock offset. */
private final ParameterDriver clockOffsetDriver;
/** Simple constructor.
* @param propagatorIndex index of the propagator related to this satellite
*/
public ObservableSatellite(final int propagatorIndex) {
this.propagatorIndex = propagatorIndex;
this.propagatorIndex = propagatorIndex;
this.clockOffsetDriver = new ParameterDriver(CLOCK_OFFSET_PREFIX + propagatorIndex,
0.0, CLOCK_OFFSET_SCALE,
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
/** Get the index of the propagator related to this satellite.
......@@ -40,4 +60,16 @@ public class ObservableSatellite {
return propagatorIndex;
}
/** Get the clock offset parameter driver.
* <p>
* The offset value is defined as the value in seconds that must be <em>subtracted</em> from
* the satellite clock reading of time to compute the real physical date. The offset
* is therefore negative if the satellite clock is slow and positive if it is fast.
* </p>
* @return clock offset parameter driver
*/
public ParameterDriver getClockOffsetDriver() {
return clockOffsetDriver;
}
}
......@@ -452,7 +452,9 @@ public class PV extends AbstractMeasurement<PV> {
final SpacecraftState[] states) {
// PV value
final TimeStampedPVCoordinates pv = states[getPropagatorsIndices().get(0)].getPVCoordinates();
final ObservableSatellite satellite = getSatellites().get(0);
final SpacecraftState state = states[satellite.getPropagatorIndex()];
final TimeStampedPVCoordinates pv = state.getPVCoordinates();
// prepare the evaluation
final EstimatedMeasurement<PV> estimated =
......
......@@ -137,7 +137,8 @@ public class Phase extends AbstractMeasurement<Phase> {
final int evaluation,
final SpacecraftState[] states) {
final SpacecraftState state = states[getPropagatorsIndices().get(0)];
final ObservableSatellite satellite = getSatellites().get(0);
final SpacecraftState state = states[satellite.getPropagatorIndex()];
// Phase derivatives are computed with respect to spacecraft state in inertial frame
// and station parameters
......
......@@ -273,7 +273,9 @@ public class Position extends AbstractMeasurement<Position> {
final SpacecraftState[] states) {
// PV value
final TimeStampedPVCoordinates pv = states[getPropagatorsIndices().get(0)].getPVCoordinates();
final ObservableSatellite satellite = getSatellites().get(0);
final SpacecraftState state = states[satellite.getPropagatorIndex()];
final TimeStampedPVCoordinates pv = state.getPVCoordinates();
// prepare the evaluation
final EstimatedMeasurement<Position> estimated =
......
......@@ -33,27 +33,43 @@ import org.orekit.utils.ParameterDriver;
import org.orekit.utils.TimeStampedFieldPVCoordinates;
import org.orekit.utils.TimeStampedPVCoordinates;
/** Class modeling a range measurement from a ground station or
* from a satellite.
/** Class modeling a range measurement from a ground station.
* <p>
* For two-way measurements, the measurement is considered
* to be a signal emitted from a ground station, reflected
* on spacecraft, and received on the same ground station.
* Its value is the elapsed time between emission and reception
* divided by 2c were c is the speed of light.
* For one-way measurements, a signal is emitted by the satellite
* and received by the ground station. The measurement value is the
* elapsed time between emission and reception multiplied by c where
* c is the speed of light.
* </p>
* <p>
* For one-way measurements, a signal is emitted by the satellite
* and received by the ground station. The measurement value
* is the elapsed time between emission and reception divided by
* the speed of light.
* For two-way measurements, the measurement is considered to be a signal
* emitted from a ground station, reflected on spacecraft, and received
* on the same ground station. Its value is the elapsed time between
* emission and reception multiplied by c/2 where c is the speed of light.
* </p>
* <p>
* The motion of both the station and the spacecraft during the signal
* flight time are taken into account. The date of the measurement
* corresponds to the reception on ground of the emitted or reflected signal.
* </p>
* <p>
* The motion of both the station and the
* spacecraft during the signal flight time are taken into
* account. The date of the measurement corresponds to the
* reception on ground of the emitted or reflected signal.
* The clock offsets of both the ground station and the satellite are taken
* into account. These offsets correspond to the values that must be subtracted
* from station (resp. satellite) reading of time to compute the real physical
* date. These offsets have two effects:
* </p>
* <ul>
* <li>as measurement date is evaluated at reception time, the real physical date
* of the measurement is the observed date to which the receiving ground station
* clock offset is subtracted</li>
* <li>as range is evaluated using the total signal time of flight, for one-way
* measurements the observed range is the real physical signal time of flight to
* which (Δtg - Δts) ⨉ c is added, where Δtg (resp. Δts) is the clock offset for the
* receiving ground station (resp. emitting satellite). A similar effect exists in
* two-way measurements but it is computed as (Δtg - Δtg) ⨉ c / 2 as the same ground
* station clock is used for initial emission and final reception and therefore it evaluates
* to zero.</li>
* </ul>
* <p>
* @author Thierry Ceolin
* @author Luc Maisonobe
* @author Maxime Journot
......@@ -168,6 +184,10 @@ public class Range extends AbstractMeasurement<Range> {
addParameterDriver(station.getPolarDriftXDriver());
addParameterDriver(station.getPolarOffsetYDriver());
addParameterDriver(station.getPolarDriftYDriver());
if (!twoWay) {
// for one way measurements, the satellite clock offset affects the measurement
addParameterDriver(satellite.getClockOffsetDriver());
}
this.station = station;
this.twoway = twoWay;
}
......@@ -192,7 +212,8 @@ public class Range extends AbstractMeasurement<Range> {
final int evaluation,
final SpacecraftState[] states) {
final SpacecraftState state = states[getPropagatorsIndices().get(0)];
final ObservableSatellite satellite = getSatellites().get(0);
final SpacecraftState state = states[satellite.getPropagatorIndex()];
// Range derivatives are computed with respect to spacecraft state in inertial frame
// and station parameters
......@@ -201,7 +222,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 - measurements parameters (clock offset, station offsets, pole, prime meridian...)
// - 6..n - measurements parameters (clock offset, station offsets, pole, prime meridian, sat clock offset...)
int nbParams = 6;
final Map<String, Integer> indices = new HashMap<>();
for (ParameterDriver driver : getParametersDrivers()) {
......@@ -280,8 +301,13 @@ public class Range extends AbstractMeasurement<Range> {
stationDownlink.toTimeStampedPVCoordinates()
});
// Clock offsets
final DerivativeStructure dtg = station.getClockOffsetDriver().getValue(factory, indices);
final DerivativeStructure dts = satellite.getClockOffsetDriver().getValue(factory, indices);
// Range value
range = tauD.multiply(Constants.SPEED_OF_LIGHT);
range = tauD.add(dtg).subtract(dts).multiply(Constants.SPEED_OF_LIGHT);
}
estimated.setEstimatedValue(range.getValue());
......
......@@ -147,7 +147,8 @@ public class RangeRate extends AbstractMeasurement<RangeRate> {
protected EstimatedMeasurement<RangeRate> theoreticalEvaluation(final int iteration, final int evaluation,
final SpacecraftState[] states) {
final SpacecraftState state = states[getPropagatorsIndices().get(0)];
final ObservableSatellite satellite = getSatellites().get(0);
final SpacecraftState state = states[satellite.getPropagatorIndex()];
// Range-rate derivatives are computed with respect to spacecraft state in inertial frame
// and station position in station's offset frame
......
......@@ -164,7 +164,8 @@ public class TurnAroundRange extends AbstractMeasurement<TurnAroundRange> {
protected EstimatedMeasurement<TurnAroundRange> theoreticalEvaluation(final int iteration, final int evaluation,
final SpacecraftState[] states) {
final SpacecraftState state = states[getPropagatorsIndices().get(0)];
final ObservableSatellite satellite = getSatellites().get(0);
final SpacecraftState state = states[satellite.getPropagatorIndex()];
// Turn around range derivatives are computed with respect to:
// - Spacecraft state in inertial frame
......
......@@ -36,7 +36,7 @@ public class InterSatellitesRangeBuilder extends AbstractMeasurementBuilder<Inte
/** Simple constructor.
* @param noiseSource noise source, may be null for generating perfect measurements
* @param receiver satellite which receives the signal and performs the measurement
* @param local satellite which receives the signal and performs the measurement
* @param remote satellite which simply emits the signal in the one-way case,
* or reflects the signal in the two-way case
* @param twoWay flag indicating whether it is a two-way measurement
......@@ -44,9 +44,9 @@ public class InterSatellitesRangeBuilder extends AbstractMeasurementBuilder<Inte
* @param baseWeight base weight
*/
public InterSatellitesRangeBuilder(final CorrelatedRandomVectorGenerator noiseSource,
final ObservableSatellite receiver, final ObservableSatellite remote,
final ObservableSatellite local, final ObservableSatellite remote,
final boolean twoWay, final double sigma, final double baseWeight) {
super(noiseSource, sigma, baseWeight, receiver, remote);
super(noiseSource, sigma, baseWeight, local, remote);
this.twoway = twoWay;
}
......
......@@ -208,8 +208,8 @@ discrete events. Here is a short list of the features offered by the library:</p
<li>orbital parameters estimation (or only a subset if desired)</li>
<li>force model parameters estimation (drag coefficients, radiation pressure coefficients,
central attraction, maneuver thrust or flow rate)</li>
<li>measurements parameters estimation (biases, station clock offset, station position, pole motion and rate,
prime meridian correction and rate)</li>
<li>measurements parameters estimation (biases, satellite clock offset, station clock offset,
station position, pole motion and rate, prime meridian correction and rate)</li>
</ul>
</li>
<li>multi-satellites orbit determination</li>
......
......@@ -20,7 +20,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hipparchus.analysis.differentiation.DSFactory;
import org.hipparchus.analysis.differentiation.DerivativeStructure;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.Precision;
import org.orekit.errors.OrekitException;
......@@ -188,8 +191,7 @@ public class ParameterDriver {
* @since 9.3
* @param referenceValue the reference value to set.
*/
public void setReferenceValue(final double referenceValue)
{
public void setReferenceValue(final double referenceValue) {
final double previousReferenceValue = this.referenceValue;
this.referenceValue = referenceValue;
for (final ParameterObserver observer : observers) {
......@@ -208,8 +210,7 @@ public class ParameterDriver {
* @since 9.3
* @param minValue the minimum value to set.
*/
public void setMinValue(final double minValue)
{
public void setMinValue(final double minValue) {
final double previousMinValue = this.minValue;
this.minValue = minValue;
for (final ParameterObserver observer : observers) {
......@@ -230,8 +231,7 @@ public class ParameterDriver {
* @since 9.3
* @param maxValue the maximum value to set.
*/
public void setMaxValue(final double maxValue)
{
public void setMaxValue(final double maxValue) {
final double previousMaxValue = this.maxValue;
this.maxValue = maxValue;
for (final ParameterObserver observer : observers) {
......@@ -252,8 +252,7 @@ public class ParameterDriver {
* @since 9.3
* @param scale the scale to set.
*/
public void setScale(final double scale)
{
public void setScale(final double scale) {
final double previousScale = this.scale;
this.scale = scale;
for (final ParameterObserver observer : observers) {
......@@ -312,6 +311,17 @@ public class ParameterDriver {
return value;
}
/** Get the value as a derivative structure.
* @param factory factory for the derivatives
* @param indices indices of the differentiation parameters in derivatives computations
* @return value with derivatives
* @since 9.3
*/
public DerivativeStructure getValue(final DSFactory factory, final Map<String, Integer> indices) {
final Integer index = indices.get(name);
return (index == null) ? factory.constant(value) : factory.variable(index, value);
}
/** Set parameter value.
* <p>
* If {@code newValue} is below {@link #getMinValue()}, it will
......
......@@ -185,8 +185,8 @@
* orbital parameters estimation (or only a subset if desired)
* force model parameters estimation (drag coefficients, radiation pressure coefficients,
central attraction, maneuver thrust or flow rate)
* measurements parameters estimation (biases, station clock offset, station position, pole motion and rate,
prime meridian correction and rate)
* measurements parameters estimation (biases, satellite clock offset, station clock offset,
station position, pole motion and rate, prime meridian correction and rate)
* multi-satellites orbit determination
* ground stations displacements due to solid tides
......
......@@ -21,6 +21,9 @@
</properties>
<body>
<release version="TBD" date="TBD" description="TBD">
<action dev="luc" type="add" issue="515">
Added clock offset parameter at satellites level for orbit determination.
</action>
<action dev="luc" type="add" issue="513">
Added clock offset parameter at ground stations level for orbit determination.
</action>
......
......@@ -223,17 +223,16 @@ public class OrbitDeterminationTest {
GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("eigen-6s-truncated", true));
//orbit determination run.
ResultOD odGNSS = run(input, false);
ResultOD odGNSS = run(input, true);
//test
//definition of the accuracy for the test
final double distanceAccuracy = 13.0;
final double distanceAccuracy = 12.0;
final double velocityAccuracy = 5.0e-3;
//test on the convergence
final int numberOfIte = 8;
final int numberOfEval = 9;
final int numberOfIte = 3;
final int numberOfEval = 5;
Assert.assertEquals(numberOfIte, odGNSS.getNumberOfIteration());
Assert.assertEquals(numberOfEval, odGNSS.getNumberOfEvaluation());
......@@ -495,7 +494,7 @@ public class OrbitDeterminationTest {
final Map<String, StationData> stations = createStationsData(parser, conventions, body);
final PVData pvData = createPVData(parser);
final ObservableSatellite satellite = new ObservableSatellite(0);
final ObservableSatellite satellite = createObservableSatellite(parser);
final Bias<Range> satRangeBias = createSatRangeBias(parser);
final OnBoardAntennaRangeModifier satAntennaRangeModifier = createSatAntennaRangeModifier(parser);
final Weights weights = createWeights(parser);
......@@ -512,7 +511,7 @@ public class OrbitDeterminationTest {
// the measurements come from a Rinex file
measurements.addAll(readRinex(new File(input.getParentFile(), fileName),
parser.getString(ParameterKey.SATELLITE_ID_IN_RINEX_FILES),
stations, satRangeBias, satAntennaRangeModifier, weights,
stations, satellite, satRangeBias, satAntennaRangeModifier, weights,
rangeOutliersManager, rangeRateOutliersManager));
} else {
// the measurements come from an Orekit custom file
......@@ -1157,6 +1156,7 @@ public class OrbitDeterminationTest {
stationAltitudes[i]);
final TopocentricFrame topo = new TopocentricFrame(body, position, stationNames[i]);
final GroundStation station = new GroundStation(topo, eopHistory, displacements);
station.getClockOffsetDriver().setReferenceValue(stationClockOffsets[i]);
station.getClockOffsetDriver().setValue(stationClockOffsets[i]);
station.getClockOffsetDriver().setMinValue(stationClockOffsetsMin[i]);
station.getClockOffsetDriver().setMaxValue(stationClockOffsetsMax[i]);
......@@ -1375,6 +1375,31 @@ public class OrbitDeterminationTest {
parser.getDouble(ParameterKey.PV_MEASUREMENTS_VELOCITY_SIGMA));
}
/** Set up satellite data.
* @param parser input file parser
* @return satellite data
* @throws NoSuchElementException if input parameters are missing
*/
private ObservableSatellite createObservableSatellite(final KeyValueFileParser<ParameterKey> parser)
throws NoSuchElementException {
ObservableSatellite obsSat = new ObservableSatellite(0);
ParameterDriver clockOffsetDriver = obsSat.getClockOffsetDriver();
if (parser.containsKey(ParameterKey.ON_BOARD_CLOCK_OFFSET)) {
clockOffsetDriver.setReferenceValue(parser.getDouble(ParameterKey.ON_BOARD_CLOCK_OFFSET));
clockOffsetDriver.setValue(parser.getDouble(ParameterKey.ON_BOARD_CLOCK_OFFSET));
}
if (parser.containsKey(ParameterKey.ON_BOARD_CLOCK_OFFSET_MIN)) {
clockOffsetDriver.setMinValue(parser.getDouble(ParameterKey.ON_BOARD_CLOCK_OFFSET_MIN));
}
if (parser.containsKey(ParameterKey.ON_BOARD_CLOCK_OFFSET_MAX)) {
clockOffsetDriver.setMaxValue(parser.getDouble(ParameterKey.ON_BOARD_CLOCK_OFFSET_MAX));
}
if (parser.containsKey(ParameterKey.ON_BOARD_CLOCK_OFFSET_ESTIMATED)) {
clockOffsetDriver.setSelected(parser.getBoolean(ParameterKey.ON_BOARD_CLOCK_OFFSET_ESTIMATED));
}
return obsSat;
}
/** Set up estimator.
* @param parser input file parser
* @param propagatorBuilder propagator builder
......@@ -1440,6 +1465,7 @@ public class OrbitDeterminationTest {
* @param file measurements file
* @param satId satellite we are interested in
* @param stations name to stations data map
* @param satellite satellite reference
* @param satRangeBias range bias due to transponder delay
* @param satAntennaRangeModifier modifier for on-board antenna offset
* @param weights base weights for measurements
......@@ -1449,6 +1475,7 @@ public class OrbitDeterminationTest {
*/
private List<ObservedMeasurement<?>> readRinex(final File file, final String satId,
final Map<String, StationData> stations,
final ObservableSatellite satellite,
final Bias<Range> satRangeBias,
final OnBoardAntennaRangeModifier satAntennaRangeModifier,
final Weights weights,
......@@ -1471,7 +1498,6 @@ public class OrbitDeterminationTest {
prnNumber = -1;
}
final Iono iono = new Iono(false);
final ObservableSatellite satellite = new ObservableSatellite(0);
final RinexLoader loader = new RinexLoader(new FileInputStream(file), file.getAbsolutePath());
for (final ObservationDataSet</