4
4
import java .util .*;
5
5
6
6
public class PositionUpdate {
7
- static Map <String , PositionUpdate > cache = new HashMap <>();
7
+ private static double originLat ; // Origin is passed-in as a command-line argument as an indication of where the receiver is located
8
+ private static double originLon ;
9
+
10
+ private static double receiverLat ; // Receiver position is calculated based on data received
11
+ private static double receiverLon ;
12
+ private static double receiverSumLat ; // Running-total of valid positions that can be used to calculate the average receiver position
13
+ private static double receiverSumLon ;
14
+ private static double receiverSumCount = 0 ; // number of valid positions received that are used to calculate the average
15
+
16
+ private static Map <String , PositionUpdate > cache = new HashMap <>();
8
17
private static Timer cacheCleanup ;
9
18
10
- static final private double dLatEven = 4.0 * 15.0 ;
11
- static final private double dLatOdd = 4.0 * 15.0 - 1.0 ;
12
- static final private double nlNumerator = 1 - Math .cos (Math .PI / (2.0 * 15.0 ));
13
- static final private double nlPi180 = Math .PI / 180.0 ;
19
+ private static final double dLatEven = 4.0 * 15.0 ;
20
+ private static final double dLatOdd = 4.0 * 15.0 - 1.0 ;
21
+ private static final double nlNumerator = 1 - Math .cos (Math .PI / (2.0 * 15.0 ));
22
+ private static final double nlPi180 = Math .PI / 180.0 ;
14
23
15
24
private CprPosition even ;
16
25
private CprPosition odd ;
@@ -51,6 +60,8 @@ private CprPosition calculate(boolean isCprEven, CprPosition newCpr) {
51
60
if (isComplete () && previous == null ) {
52
61
// We've now got a pair of odd/even frames but there was no previous position... so we must use Global calculation to get accurate position
53
62
calculateGlobal ();
63
+ // Update the receiver position only from Global updates (likely to be the first time updating from this aircraft)
64
+ PositionUpdate .receiverUpdate (current .getLat (), current .getLon ());
54
65
} else if (previous != null ) {
55
66
// We had a previous accurate position, so we can use the most recent frame to do Local calculation
56
67
calculateLocal (!isCprEven );
@@ -96,14 +107,13 @@ private void calculateLocal(boolean isOdd) {
96
107
//return;
97
108
}
98
109
99
- // TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range
100
- // TODO Should be a sanity-check here to see if the calculated movement since the last update is too far
101
-
102
110
current = new CprPosition (newLat , newLon , cpr .getSurface ());
103
111
if (current .getSurface ()) {
104
- current . validateSurface ();
112
+ validateSurface (current );
105
113
}
106
114
115
+ // TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range
116
+ // TODO Should be a sanity-check here to see if the calculated movement since the last update is too far
107
117
}
108
118
109
119
private void calculateGlobal () {
@@ -113,13 +123,8 @@ private void calculateGlobal() {
113
123
double latEven = (degrees / dLatEven ) * (cprMod (j , dLatEven ) + even .getLat ());
114
124
double latOdd = (degrees / dLatOdd ) * (cprMod (j , dLatOdd ) + odd .getLat ());
115
125
116
- if (latEven >= 270.0 && latEven <= 360.0 ) {
117
- latEven -= 360.0 ;
118
- }
119
-
120
- if (latOdd >= 270.0 && latOdd <= 360.0 ) {
121
- latOdd -= 360.0 ;
122
- }
126
+ latEven = normaliseLat (latEven );
127
+ latOdd = normaliseLat (latOdd );
123
128
124
129
double nlLatEven = NL (latEven );
125
130
double nlLatOdd = NL (latOdd );
@@ -147,31 +152,27 @@ private void calculateGlobal() {
147
152
newLat = latOdd ;
148
153
newLon = (degrees / ni ) * (cprMod (m , ni ) + odd .getLon ());
149
154
}
150
-
151
- if (newLon > 180d ) {
152
- newLon -= 360d ;
153
- }
154
-
155
- //TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range
155
+ newLon = normaliseLon (newLon );
156
156
157
157
even .setZones (nlLatEven , m );
158
158
odd .setZones (nlLatOdd , m );
159
159
160
160
current = new CprPosition (newLat , newLon , even .getSurface ());
161
161
if (current .getSurface ()) {
162
- current . validateSurface ();
162
+ validateSurface (current );
163
163
}
164
+ //TODO Should be a sanity-check here to make sure the calculated position isn't outside receiver origin range
164
165
}
165
166
166
- private double cprMod (double a , double b ) {
167
+ static private double cprMod (double a , double b ) {
167
168
return a - b * Math .floor (a /b );
168
169
}
169
170
170
- private double cprN (double nlLat , double isOdd ) {
171
+ static private double cprN (double nlLat , double isOdd ) {
171
172
return Math .max (1 , nlLat - isOdd );
172
173
}
173
174
174
- private double NL (double lat ) {
175
+ static private double NL (double lat ) {
175
176
if (lat == 0 ) return 59 ;
176
177
else if (Math .abs (lat ) == 87 ) return 2 ;
177
178
else if (Math .abs (lat ) > 87 ) return 1 ;
@@ -197,7 +198,66 @@ public boolean isExpired() {
197
198
return even .isExpired () || odd .isExpired ();
198
199
}
199
200
200
- public static void start () {
201
+ static public double normaliseLat (double lat ) {
202
+ if (lat >= 270.0 && lat <= 360.0 ) {
203
+ lat -= 360.0 ;
204
+ }
205
+ return lat ;
206
+ }
207
+
208
+ static public double normaliseLon (double lon ) {
209
+ if (lon > 180.0 ) {
210
+ lon -= 360.0 ;
211
+ }
212
+ return lon ;
213
+ }
214
+
215
+ private void validateSurface (CprPosition pos ) {
216
+ // For SurfacePositions we get 8 possible solutions: 2x latitude, 4x longitude zones at 90 degree increments
217
+ double diff ;
218
+ double test ;
219
+ double testDiff ;
220
+
221
+ // Pick the lat which is closest to the receiver
222
+ test = pos .getLat ();
223
+ diff = Math .abs (normaliseLat (test ) - receiverLat );
224
+ for (int i = 0 ; i < 1 ; i ++){
225
+ test = normaliseLat (test + 90.0 );
226
+ testDiff = Math .abs (test - receiverLat );
227
+ if (testDiff < diff ) {
228
+ diff = testDiff ;
229
+ pos .setLat (test );
230
+ }
231
+ }
232
+
233
+ // Pick the lon which is closest to the receiver
234
+ test = pos .getLon ();
235
+ diff = Math .abs (normaliseLon (test ) - receiverLon );
236
+ for (int i = 0 ; i < 3 ; i ++){
237
+ test = normaliseLon (test + 90.0 );
238
+ testDiff = Math .abs (test - receiverLon );
239
+ if (testDiff < diff ) {
240
+ diff = testDiff ;
241
+ pos .setLon (test );
242
+ }
243
+ }
244
+ }
245
+
246
+ static private void receiverUpdate (double lat , double lon ) {
247
+ if (!((lat == 0 ) && (lon == 0 ))) {
248
+ receiverSumCount ++;
249
+ receiverSumLat += lat ;
250
+ receiverSumLon += lon ;
251
+ receiverLat = receiverSumLat / receiverSumCount ;
252
+ receiverLon = receiverSumLon / receiverSumCount ;
253
+ }
254
+ }
255
+
256
+ static public void start (double originLat , double originLon ) {
257
+ PositionUpdate .originLat = originLat ;
258
+ PositionUpdate .originLon = originLon ;
259
+
260
+ receiverUpdate (originLat , originLon );
201
261
202
262
cache .clear ();
203
263
cacheCleanup .schedule (new TimerTask () {
@@ -213,7 +273,7 @@ public void run() {
213
273
}, 0 , 10_000 );
214
274
}
215
275
216
- public static void stop () {
276
+ static public void stop () {
217
277
cacheCleanup .cancel ();
218
278
cacheCleanup = null ;
219
279
0 commit comments