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.List;
20  
21  import org.hipparchus.geometry.euclidean.threed.Vector3D;
22  import org.junit.jupiter.api.Assertions;
23  import org.junit.jupiter.api.Test;
24  import org.orekit.attitudes.LofOffset;
25  import org.orekit.estimation.Context;
26  import org.orekit.estimation.EstimationTestUtils;
27  import org.orekit.estimation.measurements.EstimatedMeasurementBase;
28  import org.orekit.estimation.measurements.ObservedMeasurement;
29  import org.orekit.estimation.measurements.gnss.OneWayGNSSRange;
30  import org.orekit.estimation.measurements.gnss.OneWayGNSSRangeCreator;
31  import org.orekit.frames.LOFType;
32  import org.orekit.orbits.CartesianOrbit;
33  import org.orekit.orbits.Orbit;
34  import org.orekit.orbits.OrbitType;
35  import org.orekit.orbits.PositionAngleType;
36  import org.orekit.propagation.BoundedPropagator;
37  import org.orekit.propagation.EphemerisGenerator;
38  import org.orekit.propagation.Propagator;
39  import org.orekit.propagation.SpacecraftState;
40  import org.orekit.propagation.conversion.NumericalPropagatorBuilder;
41  import org.orekit.utils.TimeStampedPVCoordinates;
42  
43  
44  public class OnBoardAntennaOneWayGNSSRangeModifierTest {
45  
46      @Test
47      public void testPreliminary() {
48  
49          Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
50  
51          final NumericalPropagatorBuilder propagatorBuilder =
52                          context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
53                                                1.0e-6, 60.0, 0.001);
54          propagatorBuilder.setAttitudeProvider(new LofOffset(propagatorBuilder.getFrame(), LOFType.LVLH));
55  
56          // create perfect one-way GNSS range measurements without antenna offset
57          final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates();
58          final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(),
59                                                                                   original.getPosition().add(new Vector3D(1000, 2000, 3000)),
60                                                                                   original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))),
61                                                      context.initialOrbit.getFrame(),
62                                                      context.initialOrbit.getMu());
63          final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit,
64                                                                                  propagatorBuilder);
65          final EphemerisGenerator generator = closePropagator.getEphemerisGenerator();
66          closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod()));
67          final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
68          final Propagator p1 = EstimationTestUtils.createPropagator(context.initialOrbit,
69                                                                             propagatorBuilder);
70          final double localClockOffset  = 0.137e-6;
71          final double remoteClockOffset = 469.0e-6;
72          final List<ObservedMeasurement<?>> spacecraftCenteredMeasurements =
73                          EstimationTestUtils.createMeasurements(p1,
74                                                                 new OneWayGNSSRangeCreator(ephemeris,
75                                                                                            localClockOffset,
76                                                                                            remoteClockOffset,
77                                                                                            Vector3D.ZERO,
78                                                                                            Vector3D.ZERO),
79                                                                 1.0, 3.0, 300.0);
80  
81          // create perfect one-way GNSS range measurements with antenna offset
82          final double xOffset1 = -2.5;
83          final double yOffset2 =  0.8;
84          final Propagator p2 = EstimationTestUtils.createPropagator(context.initialOrbit,
85                                                                     propagatorBuilder);
86          final List<ObservedMeasurement<?>> antennaCenteredMeasurements =
87                          EstimationTestUtils.createMeasurements(p2,
88                                                                 new OneWayGNSSRangeCreator(ephemeris,
89                                                                                            localClockOffset,
90                                                                                            remoteClockOffset,
91                                                                                            new Vector3D(xOffset1, 0, 0),
92                                                                                            new Vector3D(0, yOffset2, 0)),
93                                                                 1.0, 3.0, 300.0);
94  
95          for (int i = 0; i < spacecraftCenteredMeasurements.size(); ++i) {
96              OneWayGNSSRange sr = (OneWayGNSSRange) spacecraftCenteredMeasurements.get(i);
97              OneWayGNSSRange ar = (OneWayGNSSRange) antennaCenteredMeasurements.get(i);
98              Assertions.assertEquals(0.0, sr.getDate().durationFrom(ar.getDate()), 2.0e-8);
99              Assertions.assertTrue(ar.getObservedValue()[0] - sr.getObservedValue()[0] >= -1.0);
100             Assertions.assertTrue(ar.getObservedValue()[0] - sr.getObservedValue()[0] <= -0.36);
101         }
102     }
103 
104     @Test
105     public void testEffect() {
106 
107         Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
108 
109         final NumericalPropagatorBuilder propagatorBuilder =
110                         context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
111                                               1.0e-6, 60.0, 0.001);
112         propagatorBuilder.setAttitudeProvider(new LofOffset(propagatorBuilder.getFrame(), LOFType.LVLH));
113 
114         // create perfect one-way GNSS range range measurements without antenna offset
115         final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates();
116         final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(),
117                                                                                  original.getPosition().add(new Vector3D(1000, 2000, 3000)),
118                                                                                  original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))),
119                                                     context.initialOrbit.getFrame(),
120                                                     context.initialOrbit.getMu());
121         final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit,
122                                                                                 propagatorBuilder);
123         final EphemerisGenerator generator = closePropagator.getEphemerisGenerator();
124         closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(10.0 * closeOrbit.getKeplerianPeriod()));
125         final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
126         final Propagator p1 = EstimationTestUtils.createPropagator(context.initialOrbit,
127                                                                            propagatorBuilder);
128         final double localClockOffset  = 0.137e-6;
129         final double remoteClockOffset = 469.0e-6;
130         final List<ObservedMeasurement<?>> spacecraftCenteredMeasurements =
131                         EstimationTestUtils.createMeasurements(p1,
132                                                                new OneWayGNSSRangeCreator(ephemeris,
133                                                                                           localClockOffset,
134                                                                                           remoteClockOffset),
135                                                                1.0, 3.0, 300.0);
136 
137         // create perfect one-way GNSS range measurements with antenna offset
138         final Vector3D apc1 = new Vector3D(-2.5, 0.0, 0);
139         final Vector3D apc2 = new Vector3D( 0.0, 0.8, 0);
140         final Propagator p2 = EstimationTestUtils.createPropagator(context.initialOrbit,
141                                                                    propagatorBuilder);
142         final List<ObservedMeasurement<?>> antennaCenteredMeasurements =
143                         EstimationTestUtils.createMeasurements(p2,
144                                                                new OneWayGNSSRangeCreator(ephemeris,
145                                                                                           localClockOffset,
146                                                                                           remoteClockOffset,
147                                                                                           apc1, apc2),
148                                                                1.0, 3.0, 300.0);
149 
150         final Propagator p3 = EstimationTestUtils.createPropagator(context.initialOrbit,
151                                                                    propagatorBuilder);
152 
153         OnBoardAntennaOneWayGNSSRangeModifier modifier = new OnBoardAntennaOneWayGNSSRangeModifier(apc1, apc2, p2.getAttitudeProvider());
154         for (int i = 0; i < spacecraftCenteredMeasurements.size(); ++i) {
155             OneWayGNSSRange sr = (OneWayGNSSRange) spacecraftCenteredMeasurements.get(i);
156             sr.addModifier(modifier);
157             EstimatedMeasurementBase<OneWayGNSSRange> estimated = sr.estimateWithoutDerivatives(new SpacecraftState[] { p3.propagate(sr.getDate()) });
158             OneWayGNSSRange ar = (OneWayGNSSRange) antennaCenteredMeasurements.get(i);
159             Assertions.assertEquals(0.0, sr.getDate().durationFrom(ar.getDate()), 2.0e-8);
160             Assertions.assertEquals(ar.getObservedValue()[0], estimated.getEstimatedValue()[0], 2.0e-5);
161             Assertions.assertEquals(1,
162                                     estimated.getAppliedEffects().entrySet().stream().
163                                     filter(e -> e.getKey().getEffectName().equals("mean phase center")).count());
164         }
165 
166     }
167 
168 }