1 /* Copyright 2002-2024 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.generation;
18
19 import java.util.Map;
20 import java.util.function.Function;
21 import java.util.function.ToDoubleFunction;
22
23 import org.hipparchus.random.CorrelatedRandomVectorGenerator;
24 import org.orekit.estimation.measurements.EstimationModifier;
25 import org.orekit.estimation.measurements.ObservableSatellite;
26 import org.orekit.estimation.measurements.QuadraticClockModel;
27 import org.orekit.estimation.measurements.gnss.AmbiguityCache;
28 import org.orekit.estimation.measurements.gnss.OneWayGNSSPhase;
29 import org.orekit.propagation.SpacecraftState;
30 import org.orekit.propagation.sampling.OrekitStepInterpolator;
31 import org.orekit.time.AbsoluteDate;
32 import org.orekit.utils.ParameterDriver;
33
34
35 /** Builder for {@link OneWayGNSSPhase} measurements.
36 * @author Luc Maisonobe
37 * @since 12.0
38 */
39 public class OneWayGNSSPhaseBuilder extends AbstractMeasurementBuilder<OneWayGNSSPhase> {
40
41 /** Cache for ambiguities.
42 * @since 12.1
43 */
44 private final AmbiguityCache cache;
45
46 /** Wavelength of the phase observed value [m]. */
47 private final double wavelength;
48
49 /** Satellite which receives the signal and performs the measurement. */
50 private final ObservableSatellite local;
51
52 /** Satellite which simply emits the signal. */
53 private final ObservableSatellite remote;
54
55 /** Clock model of the remote satellite that provides clock offset. */
56 private final QuadraticClockModel remoteClockModel;
57
58 /** Temporary builder for clock models.
59 * @deprecated this is a temporary field, it will be removed in Orekit 13.0
60 */
61 @Deprecated
62 private Function<AbsoluteDate, QuadraticClockModel> clockBuilder;
63
64 /** Simple constructor.
65 * @param noiseSource noise source, may be null for generating perfect measurements
66 * @param local satellite which receives the signal and performs the measurement
67 * @param remote satellite which simply emits the signal
68 * @param remoteClockModel clock model of the remote satellite that provides clock offset
69 * @param wavelength phase observed value wavelength (m)
70 * @param sigma theoretical standard deviation
71 * @param baseWeight base weight
72 * @deprecated as of 12.1, replaced by {@link #OneWayGNSSPhaseBuilder(CorrelatedRandomVectorGenerator,
73 * ObservableSatellite, ObservableSatellite, QuadraticClockModel,
74 * double, double, double, AmbiguityCache)}
75 */
76 @Deprecated
77 public OneWayGNSSPhaseBuilder(final CorrelatedRandomVectorGenerator noiseSource,
78 final ObservableSatellite local, final ObservableSatellite remote,
79 final ToDoubleFunction<AbsoluteDate> remoteClockModel,
80 final double wavelength, final double sigma, final double baseWeight) {
81 this(noiseSource, local, remote, null, wavelength, sigma, baseWeight,
82 AmbiguityCache.DEFAULT_CACHE);
83 this.clockBuilder = date -> {
84 final double cM = remoteClockModel.applyAsDouble(date.shiftedBy(-1));
85 final double c0 = remoteClockModel.applyAsDouble(date);
86 final double cP = remoteClockModel.applyAsDouble(date.shiftedBy(1));
87 return new QuadraticClockModel(date, c0, 0.5 * (cP - cM), 0.5 * (cP + cM) - c0);
88 };
89 }
90
91 /** Simple constructor.
92 * @param noiseSource noise source, may be null for generating perfect measurements
93 * @param local satellite which receives the signal and performs the measurement
94 * @param remote satellite which simply emits the signal
95 * @param remoteClockModel clock model of the remote satellite that provides clock offset
96 * @param wavelength phase observed value wavelength (m)
97 * @param sigma theoretical standard deviation
98 * @param baseWeight base weight
99 * @param cache from which ambiguity drive should come
100 * @since 12.1
101 */
102 public OneWayGNSSPhaseBuilder(final CorrelatedRandomVectorGenerator noiseSource,
103 final ObservableSatellite local, final ObservableSatellite remote,
104 final QuadraticClockModel remoteClockModel,
105 final double wavelength, final double sigma, final double baseWeight,
106 final AmbiguityCache cache) {
107 super(noiseSource, sigma, baseWeight, local, remote);
108 this.wavelength = wavelength;
109 this.local = local;
110 this.remote = remote;
111 this.remoteClockModel = remoteClockModel;
112 this.cache = cache;
113 }
114
115 /** {@inheritDoc} */
116 @Override
117 public OneWayGNSSPhase build(final AbsoluteDate date,
118 final Map<ObservableSatellite, OrekitStepInterpolator> interpolators) {
119
120 final double sigma = getTheoreticalStandardDeviation()[0];
121 final double baseWeight = getBaseWeight()[0];
122 final SpacecraftState[] relevant = new SpacecraftState[] {
123 interpolators.get(local).getInterpolatedState(date),
124 interpolators.get(remote).getInterpolatedState(date)
125 };
126
127 // temporary hack to build QuadraticClockModel from ToDoubleFunction<AbsoluteDate>
128 // for compatibility purposes
129 final QuadraticClockModel clockModel = remoteClockModel != null ?
130 remoteClockModel :
131 clockBuilder.apply(date);
132
133 // create a dummy measurement
134 final OneWayGNSSPhase dummy = new OneWayGNSSPhase(interpolators.get(remote),
135 remote.getName(),
136 clockModel, date,
137 Double.NaN, wavelength,
138 sigma, baseWeight, local,
139 cache);
140 for (final EstimationModifier<OneWayGNSSPhase> modifier : getModifiers()) {
141 dummy.addModifier(modifier);
142 }
143
144 // set a reference date for parameters missing one
145 for (final ParameterDriver driver : dummy.getParametersDrivers()) {
146 if (driver.getReferenceDate() == null) {
147 final AbsoluteDate start = getStart();
148 final AbsoluteDate end = getEnd();
149 driver.setReferenceDate(start.durationFrom(end) <= 0 ? start : end);
150 }
151 }
152
153 // estimate the perfect value of the measurement
154 double phase = dummy.estimateWithoutDerivatives(relevant).getEstimatedValue()[0];
155
156 // add the noise
157 final double[] noise = getNoise();
158 if (noise != null) {
159 phase += noise[0];
160 }
161
162 // generate measurement
163 final OneWayGNSSPhase measurement = new OneWayGNSSPhase(interpolators.get(remote),
164 remote.getName(),
165 clockModel, date,
166 phase, wavelength, sigma, baseWeight, local,
167 cache);
168 for (final EstimationModifier<OneWayGNSSPhase> modifier : getModifiers()) {
169 measurement.addModifier(modifier);
170 }
171 return measurement;
172
173 }
174
175 }