Example #1
0
        private string DecodeAirbornePositionMsg(ModeSReply msg, DateTime timestamp)
        {
            // Airborne position message --> we need subsequent messages to decode
            AirbornePositionMsg pos = (AirbornePositionMsg)msg;

            if (msg.ICAO24 == null)
            {
                return("AirbornePositionMsg: No ICAO24 found.");
            }
            string icao24 = BitConverter.ToString(msg.ICAO24).Replace("-", String.Empty);
            // check if ICAO is already stored in lookup table
            ADSBInfo info = null;

            if (!adsbinfos.TryGetValue(icao24, out info))
            {
                // no --> add new entry
                info        = new ADSBInfo();
                info.ICAO24 = icao24;
                adsbinfos.Add(icao24, info);
            }
            // adsbinfo found --> update information and calculate position
            // contains valid position?
            if (!pos.HasValidPosition)
            {
                // no --> return error meesage
                return("[" + info.ICAO24 + "] AirbornePositionMsg: No valid position found.");
            }
            info.ICAO24         = icao24;
            info.NICSupplementA = pos.NICSupplementA;
            // position calculated before
            if (!double.IsNaN(info.Lat) & !double.IsNaN(info.Lon))
            {
                try
                {
                    // use local CPR
                    double[] localpos = pos.getLocalPosition(info.Lat, info.Lon);
                    // we have a pos --> store in info and update timestamp
                    info.Lat = localpos[0];
                    info.Lon = localpos[1];
                    if (pos.HasValidAltitude)
                    {
                        info.Alt = pos.Altitude;
                    }
                    info.Timestamp = timestamp;
                    return("[" + info.ICAO24 + "] AirbornePositionMsg: Lat= " + info.Lat.ToString("F8") + ", Lon=" + info.Lon.ToString("F8") + ", Alt= " + info.Alt.ToString() + ", Time= " + info.Timestamp.ToString("HH:mm:ss.fff"));
                }
                catch (Exception ex)
                {
                }
            }
            // no position calculated before
            if (pos.IsOddFormat)
            {
                try
                {
                    // odd message
                    info.LastOddAirborne  = pos;
                    info.LastOddTimestamp = DateTime.UtcNow;
                    // check if even message was received before and not older than 10secs--> calculate global CPR
                    if ((info.LastEvenAirborne != null) && ((info.LastOddTimestamp - info.LastOddTimestamp).TotalSeconds <= 10))
                    {
                        try
                        {
                            double[] globalpos = pos.getGlobalPosition(info.LastEvenAirborne);
                            // we have a position --> store in info and update timestamp
                            info.Lat = globalpos[0];
                            info.Lon = globalpos[1];
                            if (pos.HasValidAltitude)
                            {
                                info.Alt = pos.Altitude;
                            }
                            //                        info.Timestamp = timestamp;
                            return("[" + info.ICAO24 + "] AirbornePositionMsg: Lat= " + info.Lat.ToString("F8") + ", Lon=" + info.Lon.ToString("F8") + ", Alt= " + info.Alt.ToString() + ", Time= " + info.Timestamp.ToString("HH:mm:ss.fff"));
                        }
                        catch
                        {
                            return("[" + info.ICAO24 + "] AirbornePositionMsg: Error while decoding position");
                        }
                    }
                    return("[" + info.ICAO24 + "] AirbornePositionMsg: No decoding possible yet");
                }
                catch (Exception ex)
                {
                }
            }
            // even message
            info.LastEvenAirborne  = pos;
            info.LastEvenTimestamp = DateTime.UtcNow;
            // check if odd message was received before and not older than 10secs --> calculate global CPR
            if ((info.LastOddAirborne != null) && ((info.LastEvenTimestamp - info.LastOddTimestamp).TotalSeconds <= 10))
            {
                try
                {
                    double[] globalpos = pos.getGlobalPosition(info.LastOddAirborne);
                    // we have a position --> store in info and update timestamp
                    info.Lat = globalpos[0];
                    info.Lon = globalpos[1];
                    if (pos.HasValidAltitude)
                    {
                        info.Alt = pos.Altitude;
                    }
//                    info.Timestamp = timestamp;
                    return("[" + info.ICAO24 + "] AirbornePositionMsg: Lat= " + info.Lat.ToString("F8") + ", Lon=" + info.Lon.ToString("F8") + ", Alt= " + info.Alt.ToString() + ", Time= " + info.Timestamp.ToString("HH:mm:ss.fff"));
                }
                catch
                {
                    return("[" + info.ICAO24 + "] AirbornePositionMsg: Error while decoding position");
                }
            }
            else
            {
                return("[" + info.ICAO24 + "] AirbornePositionMsg:No decoding possible yet");
            }
        }
Example #2
0
        /**
         * This method can only be used if another position report with a different format (even/odd) is available
         * and set with msg.setOtherFormatMsg(other).
         * @param other airborne position message of the other format (even/odd). Note that the time between
         *        both messages should be not longer than 10 seconds!
         * @return globally unambiguously decoded position tuple (latitude, longitude). The positional
         *         accuracy maintained by the Airborne CPR encoding will be approximately 5.1 meters.
         *         A message of the other format is needed for global decoding.
         * @throws MissingInformationException if no position information is available in one of the messages
         * @throws IllegalArgumentException if input message was emitted from a different transmitter
         * @throws PositionStraddleError if position messages straddle latitude transition
         * @throws BadFormatException other has the same format (even/odd)
         */
        public double[] getGlobalPosition(AirbornePositionMsg other)
        {
            if (!other.ICAO24.SequenceEqual(ICAO24))
            {
                throw new IllegalArgumentException(
                          string.Format("Transmitter of other message (%s) not equal to this (%s):",
                                        BitConverter.ToString(other.ICAO24).Replace("-", String.Empty), BitConverter.ToString(ICAO24).Replace("-", String.Empty)));
            }

            if (other.IsOddFormat == IsOddFormat)
            {
                throw new BadFormatException("Expected " + (IsOddFormat? "even":"odd") + " message format:" + other.ToString());
            }

            if (!horizontal_position_available)
            {
                throw new MissingInformationException("No position information available!");
            }
            if (!other.HasValidPosition)
            {
                throw new MissingInformationException("Other message has no position information.");
            }

            AirbornePositionMsg even = IsOddFormat?other:this;
            AirbornePositionMsg odd  = IsOddFormat?this:other;

            // Helper for latitude single(Number of zones NZ is set to 15)
            double Dlat0 = 360.0 / 60.0;
            double Dlat1 = 360.0 / 59.0;

            // latitude index
            double j = Math.Floor((59.0 * even.CPREncodedLat - 60.0 * odd.CPREncodedLat) / ((double)(1 << 17)) + 0.5);

            // global latitudes
            double Rlat0 = Dlat0 * (mod(j, 60) + even.CPREncodedLat / ((double)(1 << 17)));
            double Rlat1 = Dlat1 * (mod(j, 59) + odd.CPREncodedLat / ((double)(1 << 17)));

            // Southern hemisphere?
            if (Rlat0 >= 270 && Rlat0 <= 360)
            {
                Rlat0 -= 360;
            }
            if (Rlat1 >= 270 && Rlat1 <= 360)
            {
                Rlat1 -= 360;
            }

            // Northern hemisphere?
            if (Rlat0 <= -270 && Rlat0 >= -360)
            {
                Rlat0 += 360;
            }
            if (Rlat1 <= -270 && Rlat1 >= -360)
            {
                Rlat1 += 360;
            }

            // ensure that the number of even longitude zones are equal
            if (NL(Rlat0) != NL(Rlat1))
            {
                throw new PositionStraddleException(
                          "The two given position straddle a transition latitude " +
                          "and cannot be decoded. Wait for positions where they are equal.");
            }

            // Helper for longitude
            double Dlon0 = 360.0 / Math.Max(1.0, NL(Rlat0));
            double Dlon1 = 360.0 / Math.Max(1.0, NL(Rlat1) - 1);

            // longitude index
            double NL_helper = NL(IsOddFormat?Rlat1:Rlat0);         // assuming that this is the newer message
            double m         = Math.Floor((even.CPREncodedLon * (NL_helper - 1) - odd.CPREncodedLon * NL_helper) / ((double)(1 << 17)) + 0.5);

            // global longitude
            double Rlon0 = Dlon0 * (mod(m, Math.Max(1.0, NL(Rlat0))) + even.CPREncodedLon / ((double)(1 << 17)));
            double Rlon1 = Dlon1 * (mod(m, Math.Max(1.0, NL(Rlat1) - 1)) + odd.CPREncodedLon / ((double)(1 << 17)));

            // correct longitude
            if (Rlon0 < -180 && Rlon0 > -360)
            {
                Rlon0 += 360;
            }
            if (Rlon1 < -180 && Rlon1 > -360)
            {
                Rlon1 += 360;
            }
            if (Rlon0 > 180 && Rlon0 < 360)
            {
                Rlon0 -= 360;
            }
            if (Rlon1 > 180 && Rlon1 < 360)
            {
                Rlon1 -= 360;
            }

            return(new double[] { IsOddFormat?Rlat1 : Rlat0, IsOddFormat?Rlon1 : Rlon0 });
        }