1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.estimation.measurements.gnss;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.stream.Collectors;
23
24 import org.hipparchus.linear.MatrixUtils;
25 import org.hipparchus.linear.QRDecomposer;
26 import org.hipparchus.linear.RealMatrix;
27 import org.hipparchus.linear.RealVector;
28 import org.hipparchus.util.FastMath;
29 import org.orekit.errors.OrekitIllegalArgumentException;
30 import org.orekit.errors.OrekitMessages;
31 import org.orekit.utils.ParameterDriver;
32
33
34
35
36
37
38 public class AmbiguitySolver {
39
40
41 private final List<ParameterDriver> ambiguityDrivers;
42
43
44 private final IntegerLeastSquareSolver solver;
45
46
47 private final AmbiguityAcceptance acceptance;
48
49
50
51
52
53
54
55 public AmbiguitySolver(final List<ParameterDriver> ambiguityDrivers,
56 final IntegerLeastSquareSolver solver,
57 final AmbiguityAcceptance acceptance) {
58 this.ambiguityDrivers = ambiguityDrivers;
59 this.solver = solver;
60 this.acceptance = acceptance;
61 }
62
63
64
65
66 public List<ParameterDriver> getAllAmbiguityDrivers() {
67 return Collections.unmodifiableList(ambiguityDrivers);
68 }
69
70
71
72
73 protected List<ParameterDriver> getFreeAmbiguityDrivers() {
74 return ambiguityDrivers.
75 stream().
76 filter(d -> {
77 if (d.isSelected()) {
78 final double near = FastMath.rint(d.getValue());
79 final double gapMin = near - d.getMinValue();
80 final double gapMax = d.getMaxValue() - near;
81 return FastMath.max(FastMath.abs(gapMin), FastMath.abs(gapMax)) > 1.0e-15;
82 } else {
83 return false;
84 }
85 }).
86 collect(Collectors.toList());
87 }
88
89
90
91
92
93
94 protected int[] getFreeAmbiguityIndirection(final int startIndex,
95 final List<ParameterDriver> measurementsParametersDrivers) {
96
97
98 final List<ParameterDriver> freeDrivers = getFreeAmbiguityDrivers();
99 final int n = freeDrivers.size();
100 final int[] indirection = new int[n];
101 for (int i = 0; i < n; ++i) {
102 indirection[i] = -1;
103 final String name = freeDrivers.get(i).getName();
104 for (int k = 0; k < measurementsParametersDrivers.size(); ++k) {
105 if (name.equals(measurementsParametersDrivers.get(k).getName())) {
106 indirection[i] = startIndex + k;
107 break;
108 }
109 }
110 if (indirection[i] < 0) {
111
112 final StringBuilder builder = new StringBuilder();
113 for (final ParameterDriver driver : measurementsParametersDrivers) {
114 if (builder.length() > 0) {
115 builder.append(", ");
116 }
117 builder.append(driver.getName());
118 }
119 throw new OrekitIllegalArgumentException(OrekitMessages.UNSUPPORTED_PARAMETER_NAME,
120 name, builder.toString());
121 }
122 }
123
124 return indirection;
125
126 }
127
128
129
130
131 public void unFixAmbiguity(final ParameterDriver ambiguityDriver) {
132 ambiguityDriver.setMinValue(Double.NEGATIVE_INFINITY);
133 ambiguityDriver.setMaxValue(Double.POSITIVE_INFINITY);
134 }
135
136
137
138
139
140
141
142 public List<ParameterDriver> fixIntegerAmbiguities(final int startIndex,
143 final List<ParameterDriver> measurementsParametersDrivers,
144 final RealMatrix covariance) {
145
146
147 final List<ParameterDriver> ambiguities = getAllAmbiguityDrivers();
148 final double[] floatAmbiguities = ambiguities.stream().mapToDouble(d -> d.getValue()).toArray();
149 final int[] indirection = getFreeAmbiguityIndirection(startIndex, measurementsParametersDrivers);
150
151
152 final IntegerLeastSquareSolution[] candidates =
153 solver.solveILS(acceptance.numberOfCandidates(), floatAmbiguities, indirection, covariance);
154
155
156
157
158 if (solver instanceof IntegerBootstrapping && candidates.length == 0) {
159 return Collections.emptyList();
160 }
161
162
163 if (candidates.length < acceptance.numberOfCandidates()) {
164 return Collections.emptyList();
165 }
166
167
168 final IntegerLeastSquareSolution bestCandidate = acceptance.accept(candidates);
169 if (bestCandidate == null) {
170 return Collections.emptyList();
171 }
172
173
174 final long[] fixedAmbiguities = bestCandidate.getSolution();
175 final List<ParameterDriver> fixedDrivers = new ArrayList<>(indirection.length);
176 for (int i = 0; i < indirection.length; ++i) {
177 final ParameterDriver driver = measurementsParametersDrivers.get(indirection[i] - startIndex);
178 driver.setMinValue(fixedAmbiguities[i]);
179 driver.setMaxValue(fixedAmbiguities[i]);
180 fixedDrivers.add(driver);
181 }
182
183
184
185 final RealMatrix Qab = getCovMatrix(covariance, indirection);
186
187 final RealVector X = new QRDecomposer(1.0e-10).decompose(getAmbiguityMatrix(covariance, indirection)).solve(MatrixUtils.createRealVector(floatAmbiguities).
188 subtract(MatrixUtils.createRealVector(toDoubleArray(fixedAmbiguities.length, fixedAmbiguities))));
189 final RealVector Y = Qab.preMultiply(X);
190
191 for (int i = startIndex + 1; i < covariance.getColumnDimension(); i++) {
192 if (!belongTo(indirection, i)) {
193 final ParameterDriver driver = measurementsParametersDrivers.get(i - startIndex);
194 driver.setValue(driver.getValue() - Y.getEntry(i - startIndex));
195 }
196 }
197
198 return fixedDrivers;
199
200 }
201
202
203
204
205
206
207 private RealMatrix getCovMatrix(final RealMatrix cov, final int[] indirection) {
208 final RealMatrix Qab = MatrixUtils.createRealMatrix(indirection.length, cov.getColumnDimension());
209 int index = 0;
210 int iter = 0;
211 while (iter < indirection.length) {
212
213 for (int j = 0; j < cov.getColumnDimension(); j++) {
214 if (!belongTo(indirection, j)) {
215 Qab.setEntry(index, 0, cov.getEntry(index, 0));
216 }
217 }
218 index++;
219 iter++;
220 }
221 return Qab;
222 }
223
224
225
226
227
228
229 private RealMatrix getAmbiguityMatrix(final RealMatrix cov, final int[] indirection) {
230 final RealMatrix Qa = MatrixUtils.createRealMatrix(indirection.length, indirection.length);
231 for (int i = 0; i < indirection.length; i++) {
232 Qa.setEntry(i, i, cov.getEntry(indirection[i], indirection[i]));
233 for (int j = 0; j < i; j++) {
234 Qa.setEntry(i, j, cov.getEntry(indirection[i], indirection[j]));
235 Qa.setEntry(j, i, cov.getEntry(indirection[i], indirection[j]));
236 }
237 }
238 return Qa;
239 }
240
241
242
243
244
245
246 private boolean belongTo(final int[] indirection, final int pos) {
247 for (int j : indirection) {
248 if (pos == j) {
249 return true;
250 }
251 }
252 return false;
253 }
254
255
256
257
258
259
260 private double[] toDoubleArray(final int size, final long[] longArray) {
261
262 final double[] doubleArray = new double[size];
263
264 for (int index = 0; index < size; index++) {
265 doubleArray[index] = longArray[index];
266 }
267 return doubleArray;
268 }
269
270 }