1 /*
2 * Copyright (C) 2016 Alberto Irurueta Carro (alberto@irurueta.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.irurueta.ar.slam;
17
18 import com.irurueta.algebra.Matrix;
19 import com.irurueta.algebra.WrongSizeException;
20 import com.irurueta.statistics.InvalidCovarianceMatrixException;
21 import com.irurueta.statistics.MultivariateNormalDist;
22
23 import java.io.Serializable;
24
25 /**
26 * Contains control calibration data for a SLAM estimator during
27 * Kalman filtering prediction stage.
28 */
29 public abstract class BaseCalibrationData implements Serializable {
30
31 /**
32 * Length of control signal.
33 */
34 private final int controlLength;
35
36 /**
37 * Length of state in SLAM estimator.
38 */
39 private final int stateLength;
40
41 /**
42 * Control signal mean to correct biases in control signal.
43 */
44 private double[] controlMean;
45
46 /**
47 * Control signal covariance to take into account for estimation of process
48 * noise during Kalman prediction stage.
49 */
50 private Matrix controlCovariance;
51
52 /**
53 * Evaluator for distribution propagation.
54 */
55 private transient MultivariateNormalDist.JacobianEvaluator evaluator;
56
57 /**
58 * Constructor.
59 *
60 * @param controlLength length of control signal.
61 * @param stateLength length of state in SLAM estimator.
62 * @throws IllegalArgumentException if provided length is not greater than
63 * zero.
64 */
65 protected BaseCalibrationData(final int controlLength, final int stateLength) {
66 if (controlLength < 1 || stateLength < 1) {
67 throw new IllegalArgumentException("length must be greater than zero");
68 }
69
70 this.controlLength = controlLength;
71 this.stateLength = stateLength;
72 }
73
74 /**
75 * Gets length of control signal.
76 *
77 * @return length of control signal.
78 */
79 public int getControlLength() {
80 return controlLength;
81 }
82
83 /**
84 * Gets length of state in SLAM estimator.
85 *
86 * @return length of state in SLAM estimator.
87 */
88 public int getStateLength() {
89 return stateLength;
90 }
91
92 /**
93 * Gets control signal mean to correct biases in control signal.
94 *
95 * @return control signal mean.
96 */
97 public double[] getControlMean() {
98 return controlMean;
99 }
100
101 /**
102 * Sets control signal mean to correct biases in control signal.
103 *
104 * @param controlMean control signal mean.
105 * @throws IllegalArgumentException if provided array does not have expected
106 * length.
107 */
108 public void setControlMean(final double[] controlMean) {
109 if (controlMean.length != controlLength) {
110 throw new IllegalArgumentException("wrong mean length");
111 }
112
113 this.controlMean = controlMean;
114 }
115
116 /**
117 * Gets control signal covariance to take into account for estimation of
118 * process noise during Kalman prediction stage.
119 *
120 * @return control signal covariance.
121 */
122 public Matrix getControlCovariance() {
123 return controlCovariance;
124 }
125
126 /**
127 * Sets control signal covariance to take into account for estimation of
128 * process noise during Kalman prediction stage.
129 *
130 * @param controlCovariance control signal covariance.
131 * @throws IllegalArgumentException if provided covariance size is wrong.
132 */
133 public void setControlCovariance(final Matrix controlCovariance) {
134 if (controlCovariance.getRows() != controlLength || controlCovariance.getColumns() != controlLength) {
135 throw new IllegalArgumentException("wrong covariance size");
136 }
137
138 this.controlCovariance = controlCovariance;
139 }
140
141 /**
142 * Sets control signal mean and covariance to correct biases in control
143 * signal and to take into account for estimation process noise during
144 * Kalman prediction stage.
145 *
146 * @param controlMean control signal mean.
147 * @param controlCovariance control signal covariance.
148 * @throws IllegalArgumentException if provided mean or covariance do not
149 * have proper size or length.
150 */
151 public void setControlMeanAndCovariance(final double[] controlMean, final Matrix controlCovariance) {
152 if (controlMean.length != controlLength) {
153 throw new IllegalArgumentException("wrong mean length");
154 }
155 if (controlCovariance.getRows() != controlLength || controlCovariance.getColumns() != controlLength) {
156 throw new IllegalArgumentException("wrong covariance size");
157 }
158
159 this.controlMean = controlMean;
160 this.controlCovariance = controlCovariance;
161 }
162
163 /**
164 * Propagates calibrated control signal covariance using current control
165 * jacobian matrix.
166 * The propagated distribution can be used during prediction stage in Kalman
167 * filtering.
168 *
169 * @param controlJacobian current control jacobian matrix.
170 * @return propagated distribution.
171 * @throws InvalidCovarianceMatrixException if estimated covariance is not
172 * valid.
173 * @throws IllegalArgumentException if provided jacobian has invalid size.
174 */
175 public MultivariateNormalDist propagateWithControlJacobian(final Matrix controlJacobian)
176 throws InvalidCovarianceMatrixException {
177 final var dist = new MultivariateNormalDist();
178 propagateWithControlJacobian(controlJacobian, dist);
179 return dist;
180 }
181
182 /**
183 * Propagates calibrated control signal covariance using current control
184 * jacobian matrix.
185 * The propagated distribution can be used during prediction stage in Kalman
186 * filtering.
187 *
188 * @param controlJacobian current control jacobian matrix.
189 * @param result instance where propagated distribution will be stored.
190 * @throws InvalidCovarianceMatrixException if estimated covariance is not
191 * valid.
192 * @throws IllegalArgumentException if provided jacobian has invalid size.
193 */
194 public void propagateWithControlJacobian(
195 final Matrix controlJacobian, final MultivariateNormalDist result) throws InvalidCovarianceMatrixException {
196 if (controlJacobian.getRows() != stateLength || controlJacobian.getColumns() != controlLength) {
197 throw new IllegalArgumentException("wrong control jacobian size");
198 }
199
200 if (evaluator == null) {
201 evaluator = new MultivariateNormalDist.JacobianEvaluator() {
202 @Override
203 public void evaluate(final double[] x, final double[] y, final Matrix jacobian) {
204 controlJacobian.copyTo(jacobian);
205 }
206
207 @Override
208 public int getNumberOfVariables() {
209 return stateLength;
210 }
211 };
212 }
213
214 try {
215 MultivariateNormalDist.propagate(evaluator, controlMean, controlCovariance, result);
216 } catch (final WrongSizeException e) {
217 throw new InvalidCovarianceMatrixException(e);
218 }
219 }
220 }