1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.hipparchus.filtering.kalman;
18
19 import org.hipparchus.exception.MathIllegalStateException;
20 import org.hipparchus.filtering.LocalizedFilterFormats;
21 import org.hipparchus.linear.MatrixDecomposer;
22 import org.hipparchus.linear.RealMatrix;
23 import org.hipparchus.linear.RealVector;
24
25 import java.util.ArrayList;
26 import java.util.LinkedList;
27 import java.util.List;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public class KalmanSmoother implements KalmanObserver {
56
57
58 private final MatrixDecomposer decomposer;
59
60
61 private final List<SmootherData> smootherData;
62
63
64
65
66 public KalmanSmoother(final MatrixDecomposer decomposer) {
67 this.decomposer = decomposer;
68 this.smootherData = new ArrayList<>();
69 }
70
71 @Override
72 public void init(KalmanEstimate estimate) {
73
74 smootherData.add(new SmootherData(
75 estimate.getCorrected().getTime(),
76 null,
77 null,
78 estimate.getCorrected().getState(),
79 estimate.getCorrected().getCovariance(),
80 null
81 ));
82
83 }
84
85 @Override
86 public void updatePerformed(KalmanEstimate estimate) {
87
88
89
90 final RealMatrix smootherGain = decomposer
91 .decompose(estimate.getPredicted().getCovariance())
92 .solve(estimate.getStateCrossCovariance().transpose())
93 .transpose();
94 smootherData.add(new SmootherData(
95 estimate.getCorrected().getTime(),
96 estimate.getPredicted().getState(),
97 estimate.getPredicted().getCovariance(),
98 estimate.getCorrected().getState(),
99 estimate.getCorrected().getCovariance(),
100 smootherGain
101 ));
102 }
103
104
105
106
107
108
109
110 public List<ProcessEstimate> backwardsSmooth() {
111
112 if (smootherData.size() < 2) {
113 throw new MathIllegalStateException(LocalizedFilterFormats.PROCESS_AT_LEAST_ONE_MEASUREMENT);
114 }
115
116
117 final LinkedList<ProcessEstimate> smootherResults = new LinkedList<>();
118
119
120 final SmootherData lastUpdate = smootherData.get(smootherData.size() - 1);
121 ProcessEstimate smoothedState = new ProcessEstimate(lastUpdate.getTime(),
122 lastUpdate.getCorrectedState(), lastUpdate.getCorrectedCovariance());
123 smootherResults.addFirst(smoothedState);
124
125
126 for (int i = smootherData.size() - 2; i >= 0; --i) {
127
128
129 final RealMatrix smootherGain = smootherData.get(i + 1).getSmootherGain();
130
131 final RealVector smoothedMean = smootherData.get(i).getCorrectedState()
132 .add(smootherGain.operate(smoothedState.getState()
133 .subtract(smootherData.get(i + 1).getPredictedState())));
134
135 final RealMatrix smoothedCovariance = smootherData.get(i).getCorrectedCovariance()
136 .add(smootherGain.multiply(smoothedState.getCovariance()
137 .subtract(smootherData.get(i + 1).getPredictedCovariance()))
138 .multiplyTransposed(smootherGain));
139
140
141 smoothedState = new ProcessEstimate(smootherData.get(i).getTime(), smoothedMean, smoothedCovariance);
142 smootherResults.addFirst(smoothedState);
143 }
144
145 return smootherResults;
146 }
147
148
149 private static class SmootherData {
150
151 private final double time;
152
153
154 private final RealVector predictedState;
155
156
157 private final RealMatrix predictedCovariance;
158
159
160 private final RealVector correctedState;
161
162
163 private final RealMatrix correctedCovariance;
164
165
166 private final RealMatrix smootherGain;
167
168 SmootherData(final double time,
169 final RealVector predictedState,
170 final RealMatrix predictedCovariance,
171 final RealVector correctedState,
172 final RealMatrix correctedCovariance,
173 final RealMatrix smootherGain) {
174 this.time = time;
175 this.predictedState = predictedState;
176 this.predictedCovariance = predictedCovariance;
177 this.correctedState = correctedState;
178 this.correctedCovariance = correctedCovariance;
179 this.smootherGain = smootherGain;
180 }
181
182
183
184
185 public double getTime() {
186 return time;
187 }
188
189
190
191
192
193 public RealVector getPredictedState() {
194 return predictedState;
195 }
196
197
198
199
200
201 public RealMatrix getPredictedCovariance() {
202 return predictedCovariance;
203 }
204
205
206
207
208
209 public RealVector getCorrectedState() {
210 return correctedState;
211 }
212
213
214
215
216
217 public RealMatrix getCorrectedCovariance() {
218 return correctedCovariance;
219 }
220
221
222
223
224
225 public RealMatrix getSmootherGain() {
226 return smootherGain;
227 }
228 }
229
230 }