1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.estimation.measurements.modifiers;
18  
19  import java.util.Collections;
20  import java.util.List;
21  
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.orekit.estimation.measurements.EstimatedMeasurementBase;
24  import org.orekit.estimation.measurements.EstimationModifier;
25  import org.orekit.estimation.measurements.TurnAroundRange;
26  import org.orekit.frames.StaticTransform;
27  import org.orekit.propagation.SpacecraftState;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.utils.ParameterDriver;
30  import org.orekit.utils.TimeStampedPVCoordinates;
31  
32  /** On-board antenna offset effect on turn around range measurements.
33   * @author Luc Maisonobe
34   * @since 9.0
35   */
36  public class OnBoardAntennaTurnAroundRangeModifier implements EstimationModifier<TurnAroundRange> {
37  
38      /** Position of the Antenna Phase Center in satellite frame. */
39      private final Vector3D antennaPhaseCenter;
40  
41      /** Simple constructor.
42       * @param antennaPhaseCenter position of the Antenna Phase Center in satellite frame
43       */
44      public OnBoardAntennaTurnAroundRangeModifier(final Vector3D antennaPhaseCenter) {
45          this.antennaPhaseCenter = antennaPhaseCenter;
46      }
47  
48      /** {@inheritDoc} */
49      @Override
50      public String getEffectName() {
51          return "mean phase center";
52      }
53  
54      /** {@inheritDoc} */
55      @Override
56      public List<ParameterDriver> getParametersDrivers() {
57          return Collections.emptyList();
58      }
59  
60      /** {@inheritDoc} */
61      @Override
62      public void modifyWithoutDerivatives(final EstimatedMeasurementBase<TurnAroundRange> estimated) {
63  
64          // the participants are primary station at emission, spacecraft during leg 1,
65          // secondary station at rebound, spacecraft during leg 2, primary station at reception
66          final TimeStampedPVCoordinates[] participants      = estimated.getParticipants();
67          final Vector3D                   pPrimaryEmission  = participants[0].getPosition();
68          final AbsoluteDate               transitDateLeg1   = participants[1].getDate();
69          final Vector3D                   pSecondaryRebound = participants[2].getPosition();
70          final AbsoluteDate               transitDateLeg2   = participants[3].getDate();
71          final Vector3D                   pPrimaryReception = participants[4].getPosition();
72  
73          // transforms from spacecraft to inertial frame at transit dates
74          final SpacecraftState refState              = estimated.getStates()[0];
75          final SpacecraftState transitStateLeg1      = refState.shiftedBy(transitDateLeg1.durationFrom(refState.getDate()));
76          final StaticTransform spacecraftToInertLeg1 = transitStateLeg1.toStaticTransform().getInverse();
77          final SpacecraftState transitStateLeg2      = refState.shiftedBy(transitDateLeg2.durationFrom(refState.getDate()));
78          final StaticTransform spacecraftToInertLeg2 = transitStateLeg2.toStaticTransform().getInverse();
79  
80          // compute the geometrical value of the turn-around range directly from participants positions.
81          // Note that this may be different from the value returned by estimated.getEstimatedValue(),
82          // because other modifiers may already have been taken into account
83          final Vector3D pSpacecraftLeg1 = spacecraftToInertLeg1.transformPosition(Vector3D.ZERO);
84          final Vector3D pSpacecraftLeg2 = spacecraftToInertLeg2.transformPosition(Vector3D.ZERO);
85          final double turnAroundRangeUsingSpacecraftCenter =
86                          0.5 * (Vector3D.distance(pPrimaryEmission,  pSpacecraftLeg1) +
87                                 Vector3D.distance(pSpacecraftLeg1,   pSecondaryRebound)   +
88                                 Vector3D.distance(pSecondaryRebound, pSpacecraftLeg2) +
89                                 Vector3D.distance(pSpacecraftLeg2,   pPrimaryReception));
90  
91          // compute the geometrical value of the range replacing
92          // the spacecraft positions with antenna phase center positions
93          final Vector3D pAPCLeg1 = spacecraftToInertLeg1.transformPosition(antennaPhaseCenter);
94          final Vector3D pAPCLeg2 = spacecraftToInertLeg2.transformPosition(antennaPhaseCenter);
95          final double turnAroundRangeUsingAntennaPhaseCenter =
96                          0.5 * (Vector3D.distance(pPrimaryEmission,  pAPCLeg1)          +
97                                 Vector3D.distance(pAPCLeg1,          pSecondaryRebound) +
98                                 Vector3D.distance(pSecondaryRebound, pAPCLeg2)          +
99                                 Vector3D.distance(pAPCLeg2,          pPrimaryReception));
100 
101         // get the estimated value before this modifier is applied
102         final double[] value = estimated.getEstimatedValue();
103 
104         // modify the value
105         value[0] += turnAroundRangeUsingAntennaPhaseCenter - turnAroundRangeUsingSpacecraftCenter;
106         estimated.modifyEstimatedValue(this, value);
107 
108     }
109 
110 }