junzis / pyModeS

Python decoder for Mode S and ADS-B signals
GNU General Public License v3.0
536 stars 153 forks source link

pms.adsb.position function decodes surface position reports as airborne position reports #2

Closed Parlane closed 7 years ago

Parlane commented 8 years ago

The function position(msg0, msg1, t0, t1) uses the following check: if typecode(msg0) < 5 or typecode(msg0) > 18: This should be: if typecode(msg0) < 9 or typecode(msg0) > 18:

Either that, or the position function needs to support the decoding of the surface positions.

5 - 8 (inclusive) are Surface Position Messages
9 - 18 (inclusive) are Airborne Position Messages

The position decoder you have does not work for surface position messages as they need to be decoded differently and rely on either knowing the last position of the aircraft within 180NM or knowing the receiver location to work out which lat/long to use.

Also I saw some differences in output of _cprNL vs what I believe the lat->NL should be:

If lat is 0, then NL is 59 If abs(lat) = 87 then NL is 2 If abs(lat) > 87 then NL is 1

junzis commented 8 years ago
  1. Position messages for surface and airborne share the same bits format (bit 53 to 88). Difference in earlier bits represents heading and altitude distinctly, which is considered in altitude decoding.
  2. The CPR calculation is according to the function from it's original mathematical mode. It should have higher level of accuracy than lookup tables from other source (or the previous version of this tool). Beside, we don't usually see flight at North Pole either.
Parlane commented 8 years ago

Yes they share the same bit structure, but the encoding/decoding of the CPR lat/long is different for surface positions and airborne positions. With your current code the position function will return an invalid lat/long for a surface position pair of even/odd messages.

I can provide an example soon.

junzis commented 8 years ago

You are right, I just looked into the surface position functions, it is indeed different. the CPR parameters are smaller by factor of 4. I will update this part. Thanks!

Parlane commented 8 years ago

Here is an example pair, to decode this you need to know the rough receiver position which is -43.496,172.558 due to the surface position having 4 possible longitude quadrants and either a north or southern latitude :

1464241366.9347 8CC8200A3AC8F009BCDEF2000000 1464241368.1344 8FC8200A3AB8F5F893096B000000 (-43.48564406572763, 172.53941672188895)

Sorry the checksum is not valid, the box I get data from strips it for unknown reasons.

If you need more data let me know. Or if you need more information regarding the decoding of the surface positions let me know.

Parlane commented 8 years ago

@junzis I have attached the code I have used for surface position decoding:

https://gist.github.com/Parlane/10424b2eb729842a194e7dafec7755b7

It was not coded in a way that you would want to copy straight in. But hopefully it has most of what you need already.

I actually rewrote your position function completely to verify it was correct, hence the position vs old_position.

For position_surface I have a variable in there called closest_lon which you should set to the longitude of the receiver. But also the:

Rlat0 -= 90.0 Rlat1 -= 90.0

needs to be fixed if you want northern latitudes to work. I just used a basic min distance loop to work out the most likely surface position.

Also of note are the position_surface_known and position_known functions where you can use a known lat/long instead of another even/odd to work out the position. This meant that if I got a lot of odd's in a row without getting an even, I could more accurately update the position.

Hope this helps.

junzis commented 8 years ago

@Parlane Thanks for the updates. I implement locally unambiguous surface position decoding and airborne position decoding. still working on the globally unambiguous surface position decoding.

When I am trying to run your position_surface(), with the sample message you provided earlier, the result seems to be quite far apart.

Due to the complexity to determine the regions from messages themselves. And the fact that surface position is always close to airport / receivers, it maybe easier to use surface_position_with_ref() after-all.

Parlane commented 8 years ago

@junzis The lat,long reference functions should only use a lat/long of a previously decoded odd/even pair basically. No good for using the lat/long of nearby airport/receiver. But good if you are only getting in odd messages and haven't had an even for a while.

What you need is a function that takes in an even and odd surface position message as well as a lat/long of the receiver. This gets you the correct lat/long of the craft on the ground.

In my gist I called this position_surface(msg_even, msg_odd, even_time, odd_time) and the lat/long of the receiver were hard coded in:

closest_lon = 170

and the lat was hardcoded to be the southern hemisphere "Rlat0 -= 90.0 Rlat1 -= 90.0"

Parlane commented 8 years ago

The lat/long when you have an odd and even pair for surface doesn't need to be very close. It just has to be in the right quadrant of longitude and the right hemisphere. So the function has a total of 8 possible lat,long pairs which you choose the closest to your receiver position.

Parlane commented 8 years ago

I just checked, for northern hemisphere flights you just don't do these lines: "Rlat0 -= 90.0 Rlat1 -= 90.0"

junzis commented 7 years ago

This is finally completed now, in 4bafa1d. Thanks @Parlane !

Parlane commented 7 years ago

Awesome work @junzis :)