Commit 29c83046 authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

On-board antenna phase center effect on turn-around range measurements.

parent 3a5ebb94
/* Copyright 2002-2017 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.estimation.measurements.modifiers;
import java.util.Collections;
import java.util.List;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.orekit.estimation.measurements.EstimatedMeasurement;
import org.orekit.estimation.measurements.EstimationModifier;
import org.orekit.estimation.measurements.TurnAroundRange;
import org.orekit.frames.Transform;
import org.orekit.propagation.SpacecraftState;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.ParameterDriver;
import org.orekit.utils.TimeStampedPVCoordinates;
/** On-board antenna offset effect on turn around range measurements.
* @author Luc Maisonobe
* @since 9.0
*/
public class OnBoardAntennaTurnAroundRangeModifier implements EstimationModifier<TurnAroundRange> {
/** Position of the Antenna Phase Center in satellite frame. */
private final Vector3D antennaPhaseCenter;
/** Simple constructor.
* @param antennaPhaseCenter position of the Antenna Phase Center in satellite frame
*/
public OnBoardAntennaTurnAroundRangeModifier(final Vector3D antennaPhaseCenter) {
this.antennaPhaseCenter = antennaPhaseCenter;
}
/** {@inheritDoc} */
@Override
public List<ParameterDriver> getParametersDrivers() {
return Collections.emptyList();
}
/** {@inheritDoc} */
@Override
public void modify(final EstimatedMeasurement<TurnAroundRange> estimated) {
// the participants are master station at emission, spacecraft during leg 1,
// slave station at rebound, spacecraft during leg 2, master station at reception
final TimeStampedPVCoordinates[] participants = estimated.getParticipants();
final Vector3D pMasterEmission = participants[0].getPosition();
final AbsoluteDate transitDateLeg1 = participants[1].getDate();
final Vector3D pSlaveRebound = participants[2].getPosition();
final AbsoluteDate transitDateLeg2 = participants[3].getDate();
final Vector3D pMasterReception = participants[4].getPosition();
// transforms from spacecraft to inertial frame at transit dates
final int index = estimated.getObservedMeasurement().getPropagatorsIndices().get(0);
final SpacecraftState refState = estimated.getStates()[index];
final SpacecraftState transitStateLeg1 = refState.shiftedBy(transitDateLeg1.durationFrom(refState.getDate()));
final Transform spacecraftToInertLeg1 = transitStateLeg1.toTransform().getInverse();
final SpacecraftState transitStateLeg2 = refState.shiftedBy(transitDateLeg2.durationFrom(refState.getDate()));
final Transform spacecraftToInertLeg2 = transitStateLeg2.toTransform().getInverse();
// compute the geometrical value of the turn-around range directly from participants positions.
// Note that this may be different from the value returned by estimated.getEstimatedValue(),
// because other modifiers may already have been taken into account
final Vector3D pSpacecraftLeg1 = spacecraftToInertLeg1.transformPosition(Vector3D.ZERO);
final Vector3D pSpacecraftLeg2 = spacecraftToInertLeg2.transformPosition(Vector3D.ZERO);
final double turnAroundRangeUsingSpacecraftCenter =
0.5 * (Vector3D.distance(pMasterEmission, pSpacecraftLeg1) +
Vector3D.distance(pSpacecraftLeg1, pSlaveRebound) +
Vector3D.distance(pSlaveRebound, pSpacecraftLeg2) +
Vector3D.distance(pSpacecraftLeg2, pMasterReception));
// compute the geometrical value of the range replacing
// the spacecraft positions with antenna phase center positions
final Vector3D pAPCLeg1 = spacecraftToInertLeg1.transformPosition(antennaPhaseCenter);
final Vector3D pAPCLeg2 = spacecraftToInertLeg2.transformPosition(antennaPhaseCenter);
final double turnAroundRangeUsingAntennaPhaseCenter =
0.5 * (Vector3D.distance(pMasterEmission, pAPCLeg1) +
Vector3D.distance(pAPCLeg1, pSlaveRebound) +
Vector3D.distance(pSlaveRebound, pAPCLeg2) +
Vector3D.distance(pAPCLeg2, pMasterReception));
// get the estimated value before this modifier is applied
final double[] value = estimated.getEstimatedValue();
// modify the value
value[0] += turnAroundRangeUsingAntennaPhaseCenter - turnAroundRangeUsingSpacecraftCenter;
estimated.setEstimatedValue(value);
}
}
......@@ -42,9 +42,15 @@ import org.orekit.utils.TimeStampedPVCoordinates;
public class TurnAroundRangeMeasurementCreator extends MeasurementCreator {
private final Context context;
private final Vector3D antennaPhaseCenter;
public TurnAroundRangeMeasurementCreator(final Context context) {
this.context = context;
this(context, Vector3D.ZERO);
}
public TurnAroundRangeMeasurementCreator(final Context context, final Vector3D antennaPhaseCenter) {
this.context = context;
this.antennaPhaseCenter = antennaPhaseCenter;
}
/**
......@@ -79,13 +85,13 @@ public class TurnAroundRangeMeasurementCreator extends MeasurementCreator {
final GroundStation slaveStation = entry.getValue();
final AbsoluteDate date = currentState.getDate();
final Frame inertial = currentState.getFrame();
final Vector3D position = currentState.getPVCoordinates().getPosition();
final Vector3D position = currentState.toTransform().getInverse().transformPosition(antennaPhaseCenter);
final TopocentricFrame masterTopo = masterStation.getBaseFrame();
final TopocentricFrame slaveTopo = slaveStation.getBaseFrame();
// Create a TAR measurement only if elevation for both stations is higher than elevationMin°
if ((masterTopo.getElevation(position, inertial, date) > FastMath.toRadians(30.0))&&
(slaveTopo.getElevation(position, inertial, date) > FastMath.toRadians(30.0))) {
(slaveTopo.getElevation(position, inertial, date) > FastMath.toRadians(30.0))) {
// The solver used
final UnivariateSolver solver = new BracketingNthOrderBrentSolver(1.0e-12, 5);
......@@ -103,7 +109,7 @@ public class TurnAroundRangeMeasurementCreator extends MeasurementCreator {
final double slaveTauD = solver.solve(1000, new UnivariateFunction() {
public double value(final double x) throws OrekitExceptionWrapper {
final SpacecraftState transitState = currentState.shiftedBy(-x);
final double d = Vector3D.distance(transitState.getPVCoordinates().getPosition(),
final double d = Vector3D.distance(transitState.toTransform().getInverse().transformPosition(antennaPhaseCenter),
slaveStationPosition);
return d - x * Constants.SPEED_OF_LIGHT;
}
......@@ -115,7 +121,7 @@ public class TurnAroundRangeMeasurementCreator extends MeasurementCreator {
final double slaveTauU = solver.solve(1000, new UnivariateFunction() {
public double value(final double x) throws OrekitExceptionWrapper {
final SpacecraftState transitState = currentState.shiftedBy(+x);
final double d = Vector3D.distance(transitState.getPVCoordinates().getPosition(),
final double d = Vector3D.distance(transitState.toTransform().getInverse().transformPosition(antennaPhaseCenter),
slaveStationPosition);
return d - x * Constants.SPEED_OF_LIGHT;
}
......@@ -127,11 +133,11 @@ public class TurnAroundRangeMeasurementCreator extends MeasurementCreator {
// Transit state position & date for the 1st leg of the signal path
final SpacecraftState S1 = currentState.shiftedBy(-slaveTauD);
final Vector3D P1 = S1.getPVCoordinates().getPosition();
final Vector3D P1 = S1.toTransform().getInverse().transformPosition(antennaPhaseCenter);
final AbsoluteDate T1 = date.shiftedBy(-slaveTauD);
// Transit state position & date for the 2nd leg of the signal path
final Vector3D P2 = currentState.shiftedBy(+slaveTauU).getPVCoordinates().getPosition();
final Vector3D P2 = currentState.shiftedBy(+slaveTauU).toTransform().getInverse().transformPosition(antennaPhaseCenter);
final AbsoluteDate T2 = date.shiftedBy(+slaveTauU);
......
/* Copyright 2002-2017 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.estimation.measurements.modifiers;
import java.util.List;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.junit.Assert;
import org.junit.Test;
import org.orekit.attitudes.LofOffset;
import org.orekit.errors.OrekitException;
import org.orekit.estimation.Context;
import org.orekit.estimation.EstimationTestUtils;
import org.orekit.estimation.measurements.EstimatedMeasurement;
import org.orekit.estimation.measurements.ObservedMeasurement;
import org.orekit.estimation.measurements.TurnAroundRange;
import org.orekit.estimation.measurements.TurnAroundRangeMeasurementCreator;
import org.orekit.frames.LOFType;
import org.orekit.orbits.OrbitType;
import org.orekit.orbits.PositionAngle;
import org.orekit.propagation.Propagator;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.conversion.NumericalPropagatorBuilder;
public class OnBoardAntennaTurnAroundRangeModifierTest {
@Test
public void testPreliminary() throws OrekitException {
// this test does not check OnBoardAntenneTurnAroundRangeModifier at all,
// it just checks TurnAroundRangeMeasurementCreator behaves as necessary for the other test
// the *real* test is testEffect below
Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
final NumericalPropagatorBuilder propagatorBuilder =
context.createBuilder(OrbitType.KEPLERIAN, PositionAngle.TRUE, true,
1.0e-6, 60.0, 0.001);
propagatorBuilder.setAttitudeProvider(new LofOffset(propagatorBuilder.getFrame(), LOFType.LVLH));
// create perfect turn-around range measurements without antenna offset
final Propagator p1 = EstimationTestUtils.createPropagator(context.initialOrbit,
propagatorBuilder);
final List<ObservedMeasurement<?>> spacecraftCenteredMeasurements =
EstimationTestUtils.createMeasurements(p1,
new TurnAroundRangeMeasurementCreator(context, Vector3D.ZERO),
1.0, 3.0, 300.0);
// create perfect turn-around range measurements with antenna offset
final double xOffset = -2.5;
final Propagator p2 = EstimationTestUtils.createPropagator(context.initialOrbit,
propagatorBuilder);
final List<ObservedMeasurement<?>> antennaCenteredMeasurements =
EstimationTestUtils.createMeasurements(p2,
new TurnAroundRangeMeasurementCreator(context, new Vector3D(xOffset, 0, 0)),
1.0, 3.0, 300.0);
for (int i = 0; i < spacecraftCenteredMeasurements.size(); ++i) {
TurnAroundRange sr = (TurnAroundRange) spacecraftCenteredMeasurements.get(i);
TurnAroundRange ar = (TurnAroundRange) antennaCenteredMeasurements.get(i);
Assert.assertEquals(0.0, sr.getDate().durationFrom(ar.getDate()), 2.0e-8);
Assert.assertTrue(ar.getObservedValue()[0] - sr.getObservedValue()[0] >= 2.0 * xOffset);
Assert.assertTrue(ar.getObservedValue()[0] - sr.getObservedValue()[0] <= 1.8 * xOffset);
}
}
@Test
public void testEffect() throws OrekitException {
Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
final NumericalPropagatorBuilder propagatorBuilder =
context.createBuilder(OrbitType.KEPLERIAN, PositionAngle.TRUE, true,
1.0e-6, 60.0, 0.001);
propagatorBuilder.setAttitudeProvider(new LofOffset(propagatorBuilder.getFrame(), LOFType.LVLH));
// create perfect turn-around range measurements without antenna offset
final Propagator p1 = EstimationTestUtils.createPropagator(context.initialOrbit,
propagatorBuilder);
final List<ObservedMeasurement<?>> spacecraftCenteredMeasurements =
EstimationTestUtils.createMeasurements(p1,
new TurnAroundRangeMeasurementCreator(context, Vector3D.ZERO),
1.0, 3.0, 300.0);
// create perfect turn-around range measurements with antenna offset
final Vector3D apc = new Vector3D(-2.5, 0, 0);
final Propagator p2 = EstimationTestUtils.createPropagator(context.initialOrbit,
propagatorBuilder);
final List<ObservedMeasurement<?>> antennaCenteredMeasurements =
EstimationTestUtils.createMeasurements(p2,
new TurnAroundRangeMeasurementCreator(context, apc),
1.0, 3.0, 300.0);
final Propagator p3 = EstimationTestUtils.createPropagator(context.initialOrbit,
propagatorBuilder);
OnBoardAntennaTurnAroundRangeModifier modifier = new OnBoardAntennaTurnAroundRangeModifier(apc);
for (int i = 0; i < spacecraftCenteredMeasurements.size(); ++i) {
TurnAroundRange sr = (TurnAroundRange) spacecraftCenteredMeasurements.get(i);
sr.addModifier(modifier);
EstimatedMeasurement<TurnAroundRange> estimated = sr.estimate(0, 0, new SpacecraftState[] { p3.propagate(sr.getDate()) });
TurnAroundRange ar = (TurnAroundRange) antennaCenteredMeasurements.get(i);
Assert.assertEquals(0.0, sr.getDate().durationFrom(ar.getDate()), 2.0e-8);
Assert.assertEquals(ar.getObservedValue()[0], estimated.getEstimatedValue()[0], 5.0e-7);
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment