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.generation;
18  
19  import org.hipparchus.random.RandomGenerator;
20  import org.hipparchus.random.Well19937a;
21  import org.hipparchus.util.FastMath;
22  import org.junit.jupiter.api.Assertions;
23  import org.junit.jupiter.api.BeforeEach;
24  import org.orekit.estimation.Context;
25  import org.orekit.estimation.EstimationTestUtils;
26  import org.orekit.estimation.Force;
27  import org.orekit.estimation.measurements.EstimatedMeasurementBase;
28  import org.orekit.estimation.measurements.GroundStation;
29  import org.orekit.estimation.measurements.ObservableSatellite;
30  import org.orekit.estimation.measurements.ObservedMeasurement;
31  import org.orekit.orbits.OrbitType;
32  import org.orekit.orbits.PositionAngleType;
33  import org.orekit.propagation.Propagator;
34  import org.orekit.propagation.SpacecraftState;
35  import org.orekit.propagation.conversion.NumericalPropagatorBuilder;
36  import org.orekit.propagation.events.ElevationDetector;
37  import org.orekit.propagation.events.handlers.ContinueOnEvent;
38  import org.orekit.time.AbsoluteDate;
39  import org.orekit.time.FixedStepSelector;
40  import org.orekit.time.TimeScalesFactory;
41  
42  import java.util.SortedSet;
43  
44  public abstract class AbstractGroundMeasurementBuilderTest<T extends ObservedMeasurement<T>> {
45  
46      protected abstract MeasurementBuilder<T> getBuilder(RandomGenerator random,
47                                                          GroundStation groundStation,
48                                                          ObservableSatellite satellite);
49  
50      private Propagator buildPropagator() {
51          return EstimationTestUtils.createPropagator(context.initialOrbit, propagatorBuilder);
52      }
53  
54      protected void doTest(long seed, double startPeriod, double endPeriod, int expectedMeasurements, double tolerance) {
55         Generator generator = new Generator();
56         final double step = 60.0;
57         generator.addPropagator(buildPropagator()); // dummy propagator 1
58         generator.addPropagator(buildPropagator()); // dummy propagator 2
59         final ObservableSatellite satellite = generator.addPropagator(buildPropagator()); // relevant propagator 3
60         generator.addPropagator(buildPropagator()); // dummy propagator 4
61         generator.addScheduler(new EventBasedScheduler<>(getBuilder(new Well19937a(seed), context.stations.get(0), satellite),
62                                                          new FixedStepSelector(step, TimeScalesFactory.getUTC()),
63                                                          generator.getPropagator(satellite),
64                                                          EstimationTestUtils.getElevationDetector(context.stations.get(0).getBaseFrame(),
65                                                                                                   FastMath.toRadians(5.0)).
66                                                          withHandler(new ContinueOnEvent()),
67                                                          SignSemantic.FEASIBLE_MEASUREMENT_WHEN_POSITIVE));
68         final GatheringSubscriber gatherer = new GatheringSubscriber();
69         generator.addSubscriber(gatherer);
70         final double period = context.initialOrbit.getKeplerianPeriod();
71         AbsoluteDate t0     = context.initialOrbit.getDate().shiftedBy(startPeriod * period);
72         AbsoluteDate t1     = context.initialOrbit.getDate().shiftedBy(endPeriod   * period);
73         generator.generate(t0, t1);
74         SortedSet<EstimatedMeasurementBase<?>> measurements = gatherer.getGeneratedMeasurements();
75         Assertions.assertEquals(expectedMeasurements, measurements.size());
76         Propagator propagator = buildPropagator();
77         double maxError = 0;
78         AbsoluteDate previous = null;
79         AbsoluteDate tInf = t0.isBefore(t1) ? t0 : t1;
80         AbsoluteDate tSup = t0.isBefore(t1) ? t1 : t0;
81         for (EstimatedMeasurementBase<?> measurement : measurements) {
82             AbsoluteDate date = measurement.getDate();
83             double[] m = measurement.getObservedValue();
84             Assertions.assertTrue(date.compareTo(tInf) >= 0);
85             Assertions.assertTrue(date.compareTo(tSup) <= 0);
86             if (previous != null) {
87                 if (t0.isBefore(t1)) {
88                     // measurements are expected to be chronological
89                     Assertions.assertTrue(date.durationFrom(previous) >= 0.999999 * step);
90                 } else {
91                     // measurements are expected to be reverse chronological
92                     Assertions.assertTrue(previous.durationFrom(date) >= 0.999999 * step);
93                 }
94             }
95             previous = date;
96             SpacecraftState state = propagator.propagate(date);
97             double[] e = measurement.
98                 getObservedMeasurement().
99                 estimateWithoutDerivatives(new SpacecraftState[] { state }).
100                getEstimatedValue();
101            for (int i = 0; i < m.length; ++i) {
102                maxError = FastMath.max(maxError, FastMath.abs(e[i] - m[i]));
103            }
104        }
105        Assertions.assertEquals(0.0, maxError, tolerance);
106     }
107 
108     @BeforeEach
109     public void setUp() {
110         context = EstimationTestUtils.eccentricContext("regular-data:potential:tides");
111 
112         propagatorBuilder = context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true,
113                                                   1.0e-6, 300.0, 0.001, Force.POTENTIAL,
114                                                   Force.THIRD_BODY_SUN, Force.THIRD_BODY_MOON);
115     }
116 
117     Context context;
118     NumericalPropagatorBuilder propagatorBuilder;
119 
120 }