1   /* Copyright 2022-2025 Luc Maisonobe
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 org.orekit.estimation.measurements.EstimatedMeasurementBase;
20  import org.orekit.estimation.measurements.GroundReceiverMeasurement;
21  import org.orekit.estimation.measurements.GroundStation;
22  import org.orekit.frames.Frame;
23  import org.orekit.frames.Transform;
24  import org.orekit.gnss.antenna.FrequencyPattern;
25  import org.orekit.propagation.SpacecraftState;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.utils.TimeStampedPVCoordinates;
28  
29  /** Ground and on-board antennas offsets effect on range measurements.
30   * @param <T> the type of the measurement
31   * @author Luc Maisonobe
32   * @since 12.0
33   */
34  public class PhaseCentersGroundReceiverBaseModifier<T extends GroundReceiverMeasurement<T>> {
35  
36      /** Uplink offset model. */
37      private final PhaseCentersOffsetComputer uplink;
38  
39      /** Downlink offset model. */
40      private final PhaseCentersOffsetComputer downlink;
41  
42      /** Simple constructor.
43       * @param stationPattern station pattern
44       * @param satellitePattern satellite pattern
45       */
46      public PhaseCentersGroundReceiverBaseModifier(final FrequencyPattern stationPattern,
47                                                    final FrequencyPattern satellitePattern) {
48          this.uplink   = new PhaseCentersOffsetComputer(stationPattern, satellitePattern);
49          this.downlink = new PhaseCentersOffsetComputer(satellitePattern, stationPattern);
50      }
51  
52      /** Get the name of the effect modifying the measurement.
53       * @return name of the effect modifying the measurement
54       * @since 13.0
55       */
56      public String getEffectName() {
57          return "mean phase center";
58      }
59  
60      /** Compute distance modification for one way measurement.
61       * @param estimated estimated measurement to modify
62       * @return distance modification to add to raw measurement
63       */
64      public double oneWayDistanceModification(final EstimatedMeasurementBase<T> estimated) {
65  
66          // get all participants
67          // note that clock offset is compensated in participants,
68          // so the dates included there are more accurate than the measurement date
69          final TimeStampedPVCoordinates[] participants = estimated.getParticipants();
70  
71          // station at reception date
72          final Frame         inertial       = estimated.getStates()[0].getFrame();
73          final GroundStation station        = estimated.getObservedMeasurement().getStation();
74          final AbsoluteDate  receptionDate  = participants[1].getDate();
75          final Transform     stationToInert = station.getOffsetToInertial(inertial, receptionDate, false);
76  
77          // spacecraft at emission date
78          final AbsoluteDate    emissionDate      = participants[0].getDate();
79          final SpacecraftState refState          = estimated.getStates()[0];
80          final SpacecraftState emissionState     = refState.shiftedBy(emissionDate.durationFrom(refState.getDate()));
81          final Transform       spacecraftToInert = emissionState.toTransform().getInverse();
82  
83          // compute offset due to phase centers
84          return downlink.offset(spacecraftToInert, stationToInert);
85  
86      }
87  
88      /** Apply a modifier to a two-way range measurement.
89       * @param estimated estimated measurement to modify
90       * @return distance modification to add to raw measurement
91       */
92      public double twoWayDistanceModification(final EstimatedMeasurementBase<T> estimated) {
93  
94          // get all participants
95          // note that clock offset is compensated in participants,
96          // so the dates included there are more accurate than the measurement date
97          final TimeStampedPVCoordinates[] participants = estimated.getParticipants();
98  
99          // station at reception date
100         final Frame         inertial                = estimated.getStates()[0].getFrame();
101         final GroundStation station                 = estimated.getObservedMeasurement().getStation();
102         final AbsoluteDate  receptionDate           = participants[2].getDate();
103         final Transform     stationToInertReception = station.getOffsetToInertial(inertial, receptionDate, false);
104 
105         // transform from spacecraft to inertial frame at transit date
106         final AbsoluteDate    transitDate           = participants[1].getDate();
107         final SpacecraftState refState              = estimated.getStates()[0];
108         final SpacecraftState transitState          = refState.shiftedBy(transitDate.durationFrom(refState.getDate()));
109         final Transform       spacecraftToInert     = transitState.toTransform().getInverse();
110 
111         // station at emission date
112         final AbsoluteDate emissionDate             = participants[0].getDate();
113         final Transform    stationToInertEmission   = station.getOffsetToInertial(inertial, emissionDate, true);
114 
115         // compute offsets due to phase centers
116         final double uplinkOffset   = uplink.offset(stationToInertEmission, spacecraftToInert);
117         final double downlinkOffset = downlink.offset(spacecraftToInert, stationToInertReception);
118 
119         return 0.5 * (uplinkOffset + downlinkOffset);
120 
121     }
122 
123 }