1 /* Copyright 2002-2021 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 java.util.List;
20 import java.util.SortedSet;
21 import java.util.TreeSet;
22
23 import org.hipparchus.ode.events.Action;
24 import org.orekit.estimation.measurements.ObservedMeasurement;
25 import org.orekit.propagation.Propagator;
26 import org.orekit.propagation.SpacecraftState;
27 import org.orekit.propagation.events.AdapterDetector;
28 import org.orekit.propagation.events.EventDetector;
29 import org.orekit.propagation.sampling.OrekitStepInterpolator;
30 import org.orekit.time.AbsoluteDate;
31 import org.orekit.time.DatesSelector;
32 import org.orekit.utils.TimeSpanMap;
33
34
35 /** {@link Scheduler} based on {@link EventDetector} for generating measurements sequences.
36 * <p>
37 * Event-based schedulers generate measurements following a repetitive pattern when the
38 * a {@link EventDetector detector} provided at construction is in a {@link SignSemantic
39 * measurement feasible} state. It is important that the sign of the g function of the underlying
40 * event detector is not arbitrary, but has a semantic meaning, e.g. in or out,
41 * true or false. This class works well with event detectors that detect entry to or exit
42 * from a region, e.g. {@link org.orekit.propagation.events.EclipseDetector EclipseDetector},
43 * {@link org.orekit.propagation.events.ElevationDetector ElevationDetector}, {@link
44 * org.orekit.propagation.events.LatitudeCrossingDetector LatitudeCrossingDetector}. Using this
45 * scheduler with detectors that are not based on entry to or exit from a region, e.g. {@link
46 * org.orekit.propagation.events.DateDetector DateDetector}, {@link
47 * org.orekit.propagation.events.LongitudeCrossingDetector LongitudeCrossingDetector}, will likely
48 * lead to unexpected results.
49 * </p>
50 * <p>
51 * The repetitive pattern can be either a continuous stream of measurements separated by
52 * a constant step (for example one measurement every 60s), or several sequences of measurements
53 * at high rate up to a maximum number, with a rest period between sequences (for example
54 * sequences of up to 256 measurements every 100ms with 300s between each sequence).
55 * </p>
56 * @param <T> the type of the measurement
57 * @author Luc Maisonobe
58 * @since 9.3
59 */
60 public class EventBasedScheduler<T extends ObservedMeasurement<T>> extends AbstractScheduler<T> {
61
62 /** Semantic of the detector g function sign to use. */
63 private final SignSemantic signSemantic;
64
65 /** Feasibility status. */
66 private TimeSpanMap<Boolean> feasibility;
67
68 /** Propagation direction. */
69 private boolean forward;
70
71 /** Simple constructor.
72 * <p>
73 * The event detector instance should <em>not</em> be already bound to the propagator.
74 * It will be wrapped in an {@link AdapterDetector adapter} in order to manage time
75 * ranges when measurements are feasible. The wrapping adapter will be automatically
76 * {@link Propagator#addEventDetector(EventDetector) added} to the propagator by this
77 * constructor.
78 * </p>
79 * <p>
80 * BEWARE! Dates selectors often store internally the last selected dates, so they are not
81 * reusable across several {@link EventBasedScheduler instances}. A separate selector
82 * should be used for each scheduler.
83 * </p>
84 * @param builder builder for individual measurements
85 * @param selector selector for dates (beware that selectors are generally not
86 * reusable across several {@link EventBasedScheduler instances}, each selector should
87 * be dedicated to one scheduler
88 * @param propagator propagator associated with this scheduler
89 * @param detector detector for checking measurements feasibility
90 * @param signSemantic semantic of the detector g function sign to use
91 */
92 public EventBasedScheduler(final MeasurementBuilder<T> builder, final DatesSelector selector,
93 final Propagator propagator,
94 final EventDetector detector, final SignSemantic signSemantic) {
95 super(builder, selector);
96 this.signSemantic = signSemantic;
97 this.feasibility = new TimeSpanMap<Boolean>(Boolean.FALSE);
98 this.forward = true;
99 propagator.addEventDetector(new FeasibilityAdapter(detector));
100 }
101
102 /** {@inheritDoc} */
103 @Override
104 public SortedSet<T> generate(final List<OrekitStepInterpolator> interpolators) {
105
106 // select dates in the current step, using arbitrarily interpolator 0
107 // as all interpolators cover the same range
108 final List<AbsoluteDate> dates = getSelector().selectDates(interpolators.get(0).getPreviousState().getDate(),
109 interpolators.get(0).getCurrentState().getDate());
110
111 // generate measurements when feasible
112 final SortedSet<T> measurements = new TreeSet<>();
113 for (final AbsoluteDate date : dates) {
114 if (feasibility.get(date)) {
115 // a measurement is feasible at this date
116
117 // interpolate states at measurement date
118 final SpacecraftState[] states = new SpacecraftState[interpolators.size()];
119 for (int i = 0; i < states.length; ++i) {
120 states[i] = interpolators.get(i).getInterpolatedState(date);
121 }
122
123 // generate measurement
124 measurements.add(getBuilder().build(states));
125
126 }
127 }
128
129 return measurements;
130
131 }
132
133 /** Adapter for managing feasibility status changes. */
134 private class FeasibilityAdapter extends AdapterDetector {
135
136 /** Build an adaptor wrapping an existing detector.
137 * @param detector detector to wrap
138 */
139 FeasibilityAdapter(final EventDetector detector) {
140 super(detector);
141 }
142
143 /** {@inheritDoc} */
144 @Override
145 public void init(final SpacecraftState s0, final AbsoluteDate t) {
146 super.init(s0, t);
147 forward = t.compareTo(s0.getDate()) > 0;
148 feasibility = new TimeSpanMap<Boolean>(signSemantic.measurementIsFeasible(g(s0)));
149 }
150
151 /** {@inheritDoc} */
152 @Override
153 public Action eventOccurred(final SpacecraftState s, final boolean increasing) {
154
155 // find the feasibility status AFTER the current date
156 final boolean statusAfter = signSemantic.measurementIsFeasible(increasing ? +1 : -1);
157
158 // store either status or its opposite according to propagation direction
159 if (forward) {
160 // forward propagation
161 feasibility.addValidAfter(statusAfter, s.getDate());
162 } else {
163 // backward propagation
164 feasibility.addValidBefore(!statusAfter, s.getDate());
165 }
166
167 // delegate to wrapped detector
168 return super.eventOccurred(s, increasing);
169
170 }
171
172 }
173
174 }