/// <summary>
        /// Copies the settings of the NMEA Emulator.
        /// </summary>
        /// <returns> A new NMEA Emulator with the same settings. </returns>
        //public override Emulator Clone()
        //{
        //    // Make a new emulator
        //    NmeaEmulator emulator = (NmeaEmulator)Clone(new NmeaEmulator());

        //    emulator._HorizontalDOP = _HorizontalDOP;
        //    emulator._VerticalDOP = _VerticalDOP;
        //    emulator._MeanDOP = _MeanDOP;
        //    emulator._FixMode = _FixMode;
        //    emulator._FixStatus = _FixStatus;
        //    emulator._FixMethod = _FixMethod;
        //    emulator._FixQuality = _FixQuality;
        //    emulator._MagneticVariation = _MagneticVariation;

        //    emulator._minHDOP = _minHDOP;
        //    emulator._maxHDOP = _maxHDOP;
        //    emulator._minVDOP = _minVDOP;
        //    emulator._maxVDOP = _maxVDOP;

        //    return emulator;
        //}

        public override void Randomize()
        {
            // Randomize the base emulation for speed/bearing
            base.Randomize();

            _HorizontalDOP = new DilutionOfPrecision((float)(Seed.NextDouble() * (_maxHDOP - _minHDOP) + _minHDOP));
            _VerticalDOP = new DilutionOfPrecision((float)(Seed.NextDouble() * (_maxVDOP - _minVDOP) + _minVDOP));

            // Mean is hypotenuse of the (X,Y,Z,n) axes.
            _MeanDOP = new DilutionOfPrecision((float)Math.Sqrt(Math.Pow(_HorizontalDOP.Value, 2) + Math.Pow(_VerticalDOP.Value, 2)));

            lock (Satellites)
            {
                if (Satellites.Count == 0)
                {
                    int sats = Seed.Next(4, 12);

                    //Satellites.Add(new Satellite(32, new Azimuth(225), new Elevation(45), new SignalToNoiseRatio(25)));

                    Satellites.Add(new Satellite(32, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 1)
                        Satellites.Add(new Satellite(24, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 2)
                        Satellites.Add(new Satellite(25, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 3)
                        Satellites.Add(new Satellite(26, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 4)
                        Satellites.Add(new Satellite(27, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 5)
                        Satellites.Add(new Satellite(16, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 6)
                        Satellites.Add(new Satellite(14, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 7)
                        Satellites.Add(new Satellite(6, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 8)
                        Satellites.Add(new Satellite(7, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 9)
                        Satellites.Add(new Satellite(4, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 10)
                        Satellites.Add(new Satellite(19, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 11)
                        Satellites.Add(new Satellite(8, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                }
            }

            SetRandom(true);
        }
        public void Randomize(
            Random seed, 
            Speed speedLow, 
            Speed speedHigh, 
            Azimuth bearingStart, 
            Azimuth bearingArc,
            DilutionOfPrecision minHDOP,
            DilutionOfPrecision maxHDOP,
            DilutionOfPrecision minVDOP,
            DilutionOfPrecision maxVDOP)
        {
            base.Randomize(seed, speedLow, speedHigh, bearingStart, bearingArc);

            _minHDOP = minHDOP.Value;
            _maxHDOP = maxHDOP.Value;
            _minVDOP = minVDOP.Value;
            _maxVDOP = maxVDOP.Value;

            SetRandom(true);
        }
Exemple #3
0
 /// <summary>
 /// Return a filtered Position3D from the specified parameters
 /// </summary>
 /// <param name="gpsPosition">The GPS position.</param>
 /// <param name="deviceError">The device error.</param>
 /// <param name="horizontalDOP">The horizontal DOP.</param>
 /// <param name="verticalDOP">The vertical DOP.</param>
 /// <param name="bearing">The bearing.</param>
 /// <param name="speed">The speed.</param>
 /// <returns></returns>
 public abstract Position3D Filter(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed);
        /// <summary>
        /// Adds a new observation and applies the filter.
        /// </summary>
        /// <param name="gpsPosition"> The new observation to add to the filter. </param>
        /// <param name="deviceError"> Does not currently affect position averaging. </param>
        /// <param name="horizontalDOP"> Does not currently affect position averaging. </param>
        /// <param name="verticalDOP"> Does not currently affect position averaging. </param>
        /// <param name="bearing"> Does not currently affect position averaging. </param>
        /// <param name="speed"> Does not currently affect position averaging. </param>
        /// <remarks>
        /// This method updates the FilteredLocation property without consideration for SampleCount.
        /// </remarks>
        public override Position3D Filter(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed)
        {
            this._samples.Add(gpsPosition);
            this._sampleTimes.Add(DateTime.Now);

            int count = this._samples.Count;
            int timeCount = this._sampleTimes.Count;
            int maxCount = 0;

            // Only average the number of samples specified in the constructor
            while (count > _sampleCount)
            {
                this._samples.RemoveAt(0);
                count--;
                maxCount++;
            }

            // Only 2 times are needed, oldest and most recent.
            // Try to remove as many as were removed from the sample collection.
            while (timeCount > 2 && maxCount > 0)
            {
                this._sampleTimes.RemoveAt(0);
                timeCount--;
            }

            Filter();

            return _filteredPositon;
        }
        /// <summary>
        /// Initializes the Kalman Filter using an initial observation (position)
        /// </summary>
        /// <param name="gpsPosition">The position at which tfilter is to begin opperating.</param>
        /// <param name="deviceError">A distance measure of device error</param>
        /// <param name="horizontalDOP">The horizontal dilution of precision</param>
        /// <param name="verticalDOP">The vertical dilution of precision</param>
        /// <param name="ellipsoid">The ellipsoid</param>
        public void Initialize(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Ellipsoid ellipsoid)
        {
            double fail = horizontalDOP.Value * verticalDOP.Value * deviceError.Value;
            if (fail == 0 || double.IsNaN(fail) || double.IsInfinity(fail))
            {
                throw new ArgumentException(
                    "Parameters deviceError, horizontalDOP and verticalDOP must be greater than zero.");
            }

            _currentState = new KalmanSystemState(gpsPosition, deviceError, horizontalDOP, verticalDOP, ellipsoid);
        }
 /// <summary>
 /// Initializes the Kalman Filter using an initial observation (position)
 /// </summary>
 /// <param name="gpsPosition">The position at which tfilter is to begin opperating.</param>
 /// <param name="deviceError">Distance of the error</param>
 /// <param name="meanDOP">The mean dilution of precision</param>
 public void Initialize(Position gpsPosition, Distance deviceError, DilutionOfPrecision meanDOP)
 {
     Initialize(gpsPosition, deviceError, meanDOP, meanDOP, Ellipsoid.Default);
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="KalmanSystemState"/> struct.
        /// </summary>
        /// <param name="gpsPosition">The GPS position.</param>
        /// <param name="deviceError">The device error.</param>
        /// <param name="horizontalDOP">The horizontal DOP.</param>
        /// <param name="verticalDOP">The vertical DOP.</param>
        /// <param name="ellipsoid">The ellipsoid.</param>
        /// <param name="u">The u.</param>
        /// <param name="x">The x.</param>
        /// <param name="z">The z.</param>
        /// <param name="a">A.</param>
        /// <param name="b">The b.</param>
        /// <param name="h">The h.</param>
        /// <param name="p">The p.</param>
        /// <param name="q">The q.</param>
        /// <param name="r">The r.</param>
        internal KalmanSystemState(
    Position3D gpsPosition, Distance deviceError,
    DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP,
    Ellipsoid ellipsoid,
    CartesianPoint u, CartesianPoint x, CartesianPoint z,
    SquareMatrix3D a, SquareMatrix3D b, SquareMatrix3D h,
    SquareMatrix3D p, SquareMatrix3D q, SquareMatrix3D r)
        {
            _deviceError = deviceError.IsEmpty ? DilutionOfPrecision.CurrentAverageDevicePrecision.Value : deviceError.Value;
            _horizontalDOP = horizontalDOP.IsEmpty ? DilutionOfPrecision.Good.Value : horizontalDOP.Value;
            _verticalDOP = verticalDOP.IsEmpty ? DilutionOfPrecision.Good.Value : verticalDOP.Value;
            _ellipsoid = ellipsoid ?? Ellipsoid.Default;

            double hCovariance = _deviceError * _horizontalDOP;
            double vCovariance = _deviceError * _verticalDOP;

            _u = u.IsInvalid ? CartesianPoint.Empty : u;
            _x = x;
            _z = z.IsInvalid ? CartesianPoint.Empty : z;

            _a = a ?? new SquareMatrix3D();
            _b = b ?? new SquareMatrix3D();
            _h = h ?? new SquareMatrix3D();
            _p = p ?? new SquareMatrix3D();
            _q = q ?? SquareMatrix3D.Default(0);
            _r = r ?? new SquareMatrix3D(
                          hCovariance, 0, 0,
                          0, hCovariance, 0,
                          0, 0, vCovariance);

            _interval = 0;

            _errorState = Math.Sqrt(Math.Pow(hCovariance, 2) + Math.Pow(vCovariance, 2));

            _delay = TimeSpan.MaxValue;
            _lastObservation = DateTime.MinValue;

            if (!gpsPosition.IsEmpty)
                Initialize(gpsPosition);
        }
        /// <summary>
        /// Called when [sentence changed].
        /// </summary>
        protected override void OnSentenceChanged()
        {
            // Process the basic sentence elements
            base.OnSentenceChanged();

            // Cache the word array
            string[] words = Words;
            int wordCount = words.Length;

            // Do we have enough words to parse the UTC date/time?
            if (wordCount >= 2 && words[0].Length != 0 && words[1].Length != 0)
            {
                #region Parse the UTC time

                string utcTimeWord = words[0];
                int utcHours = int.Parse(utcTimeWord.Substring(0, 2), NmeaCultureInfo);
                int utcMinutes = int.Parse(utcTimeWord.Substring(2, 2), NmeaCultureInfo);
                int utcSeconds = int.Parse(utcTimeWord.Substring(4, 2), NmeaCultureInfo);
                int utcMilliseconds = Convert.ToInt32(float.Parse(utcTimeWord.Substring(6), NmeaCultureInfo) * 1000, NmeaCultureInfo);

                #endregion Parse the UTC time

                #region Parse the UTC date

                string utcDateWord = words[1];
                int utcMonth = int.Parse(utcDateWord.Substring(0, 2), NmeaCultureInfo);
                int utcDay = int.Parse(utcDateWord.Substring(2, 2), NmeaCultureInfo);
                int utcYear = int.Parse(utcDateWord.Substring(4, 2), NmeaCultureInfo) + 2000;

                #endregion Parse the UTC date

                #region Build a UTC date/time

                _utcDateTime = new DateTime(utcYear, utcMonth, utcDay, utcHours, utcMinutes, utcSeconds, utcMilliseconds, DateTimeKind.Utc);

                #endregion Build a UTC date/time
            }
            else
            {
                // The UTC date/time is invalid
                _utcDateTime = DateTime.MinValue;
            }

            // Do we have enough data to parse the location?
            if (wordCount >= 6 && words[2].Length != 0 && words[3].Length != 0 && words[4].Length != 0 && words[5].Length != 0)
            {
                #region Parse the latitude

                string latitudeWord = words[2];
                int latitudeHours = int.Parse(latitudeWord.Substring(0, 2), NmeaCultureInfo);
                double latitudeDecimalMinutes = double.Parse(latitudeWord.Substring(2), NmeaCultureInfo);
                LatitudeHemisphere latitudeHemisphere =
                    words[3].Equals("N", StringComparison.OrdinalIgnoreCase) ? LatitudeHemisphere.North : LatitudeHemisphere.South;

                #endregion Parse the latitude

                #region Parse the longitude

                string longitudeWord = words[4];
                int longitudeHours = int.Parse(longitudeWord.Substring(0, 3), NmeaCultureInfo);
                double longitudeDecimalMinutes = double.Parse(longitudeWord.Substring(3), NmeaCultureInfo);
                LongitudeHemisphere longitudeHemisphere =
                    words[5].Equals("E", StringComparison.OrdinalIgnoreCase) ? LongitudeHemisphere.East : LongitudeHemisphere.West;

                #endregion Parse the longitude

                #region Build a Position from the latitude and longitude

                _position = new Position(
                                new Latitude(latitudeHours, latitudeDecimalMinutes, latitudeHemisphere),
                                new Longitude(longitudeHours, longitudeDecimalMinutes, longitudeHemisphere));

                #endregion Build a Position from the latitude and longitude
            }

            // Do we have enough data for the fix quality?
            if (wordCount > 7 && words[7].Length != 0)
            {
                switch (Convert.ToInt32(words[7], NmeaCultureInfo))
                {
                    case 0:
                        _fixQuality = FixQuality.NoFix;
                        break;
                    case 1:
                        _fixQuality = FixQuality.GpsFix;
                        break;
                    case 2:
                        _fixQuality = FixQuality.DifferentialGpsFix;
                        break;
                    case 3:
                        _fixQuality = FixQuality.PulsePerSecond;
                        break;
                    case 4:
                        _fixQuality = FixQuality.FixedRealTimeKinematic;
                        break;
                    case 5:
                        _fixQuality = FixQuality.FloatRealTimeKinematic;
                        break;
                    case 6:
                        _fixQuality = FixQuality.Estimated;
                        break;
                    case 7:
                        _fixQuality = FixQuality.ManualInput;
                        break;
                    case 8:
                        _fixQuality = FixQuality.Simulated;
                        break;
                    default:
                        _fixQuality = FixQuality.Unknown;
                        break;
                }
            }
            else
            {
                // The fix quality is invalid
                _fixQuality = FixQuality.Unknown;
            }

            // Process the fixed satellite count
            //_fixedSatelliteCount = wordCount > 8 ? int.Parse(Words[8], NmeaCultureInfo) : 0;

            // Process the mean DOP
            if (wordCount > 9 && Words[9].Length != 0)
                _meanDilutionOfPrecision = new DilutionOfPrecision(float.Parse(Words[9], NmeaCultureInfo));
            else
                _meanDilutionOfPrecision = DilutionOfPrecision.Maximum;

            // Altitude above ellipsoid
            if (wordCount > 10 && Words[10].Length != 0)
                _altitudeAboveEllipsoid = new Distance(double.Parse(Words[10], NmeaCultureInfo), DistanceUnit.Meters).ToLocalUnitType();
            else
                _altitudeAboveEllipsoid = Distance.Empty;
        }
 public void Initialize(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision meanDOP, Ellipsoid ellipsoid)
 {
     Initialize(gpsPosition, deviceError, meanDOP, meanDOP, ellipsoid);
 }
 public void Initialize(Position3D gpsPosition, DilutionOfPrecision meanDOP)
 {
     Initialize(gpsPosition, DilutionOfPrecision.CurrentAverageDevicePrecision, meanDOP, meanDOP, Ellipsoid.Default);
 }
 public void Initialize(Position gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Ellipsoid ellipsoid)
 {
     _currentState = new KalmanSystemState(new Position3D(gpsPosition), deviceError, horizontalDOP, verticalDOP, ellipsoid);
 }
 public void Initialize(Position gpsPosition, Distance deviceError, DilutionOfPrecision meanDOP)
 {
     Initialize(gpsPosition, deviceError, meanDOP, meanDOP, Ellipsoid.Default);
 }
        public void UpdateState(Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed, Position3D z)
        {
            if (this.x.IsInvalid)
            {
                Initialize(z);
                return;
            }

            // More insanity
            double fail = horizontalDOP.Value * verticalDOP.Value * deviceError.Value;

            if (fail == 0 || double.IsNaN(fail) || double.IsInfinity(fail))
            {
                throw new ArgumentException(
                          "Covariance values are invalid. Parameters deviceError, horizontalDOP and verticalDOP must be greater than zero.");
            }

            this._deviceError   = deviceError.Value;
            this._horizontalDOP = horizontalDOP.Value;
            this._verticalDOP   = verticalDOP.Value;

            double hCovariance = this._deviceError * this._horizontalDOP;
            double vCovariance = this._deviceError * this._verticalDOP;

            // Setup the observation covariance (measurement error)
            this.R = new SquareMatrix3D(
                hCovariance, 0, 0,
                0, hCovariance, 0,
                0, 0, vCovariance);

            #region Process Noise Estimation

            // Get the translation of the last correction
            CartesianPoint subX = this.x.ToPosition3D(_ellipsoid)
                                  .TranslateTo(bearing, speed.ToDistance(_delay), _ellipsoid)
                                  .ToCartesianPoint();

            // Get the vector of the translation and the last observation
            //CartesianPoint w = (subX - this.z);
            CartesianPoint w =
                new CartesianPoint(
                    Distance.FromMeters(subX.X.Value - this.z.X.Value),   // Values are in meters
                    Distance.FromMeters(subX.Y.Value - this.z.Y.Value),   // Values are in meters
                    Distance.FromMeters(subX.Z.Value - this.z.Z.Value));  // Values are in meters

            // Setup the noise covariance (process error)
            this.Q = new SquareMatrix3D(
                Math.Abs(w.X.Value), 0, 0,
                0, Math.Abs(w.Y.Value), 0,
                0, 0, Math.Abs(w.Z.Value));

            #endregion

            // Update the observation state
            this.z = z.ToCartesianPoint(_ellipsoid);

            #region State vector prediction and covariance

            //s.x = s.A*s.x + s.B*s.u;
            //this.x = this.A * this.x + this.B * this.u;
            CartesianPoint Ax = this.A.TransformVector(x);
            CartesianPoint Bu = this.B.TransformVector(u);
            this.x =
                new CartesianPoint(
                    Distance.FromMeters(Ax.X.Value + Bu.X.Value),
                    Distance.FromMeters(Ax.Y.Value + Bu.Y.Value),
                    Distance.FromMeters(Ax.Z.Value + Bu.Z.Value));

            //s.P = s.A * s.P * s.A' + s.Q;
            this.P = this.A * this.P * SquareMatrix3D.Transpose(this.A) + this.Q;

            #endregion

            #region Kalman gain factor

            //K = s.P*s.H'*inv(s.H*s.P*s.H'+s.R);
            SquareMatrix3D Ht = SquareMatrix3D.Transpose(this.H);
            SquareMatrix3D K  = this.P * Ht * SquareMatrix3D.Invert(this.H * this.P * Ht + this.R);

            #endregion

            #region Observational correction

            //s.x = s.x + K*(s.z-s.H*s.x);
            //this.x = this.x + K * (this.z - this.H * this.x);
            CartesianPoint Hx  = this.H.TransformVector(x);
            CartesianPoint zHx = new CartesianPoint(
                Distance.FromMeters(this.z.X.Value - Hx.X.Value),
                Distance.FromMeters(this.z.Y.Value - Hx.Y.Value),
                Distance.FromMeters(this.z.Z.Value - Hx.Z.Value));
            CartesianPoint kzHx = K.TransformVector(zHx);
            this.x =
                new CartesianPoint(
                    Distance.FromMeters(this.x.X.Value + kzHx.X.Value),
                    Distance.FromMeters(this.x.Y.Value + kzHx.Y.Value),
                    Distance.FromMeters(this.x.Z.Value + kzHx.Z.Value));

            //s.P = s.P - K*s.H*s.P;
            this.P = this.P - K * this.H * this.P;

            #endregion

            // Bump the state count
            this._interval++;

            // Calculate the average error for the system stste.
            this._errorState = (this._errorState + Math.Sqrt(Math.Pow(hCovariance, 2) + Math.Pow(vCovariance, 2))) * .5f;

            // Calculate the interval between samples
            DateTime now = DateTime.Now;
            this._delay           = now.Subtract(_lastObservation);
            this._lastObservation = now;
        }
 public void UpdateState(DilutionOfPrecision currentDOP, Position3D z)
 {
     UpdateState(Distance.FromMeters(_deviceError), currentDOP, currentDOP, Azimuth.Empty, Speed.AtRest, z);
 }
        protected override void OnSentenceChanged()
        {
            // First, process the basic info for the sentence
            base.OnSentenceChanged();

            // Cache the sentence words
            string[] words = base.Words;
            int wordCount = words.Length;

            #region Fix mode

            if (wordCount >= 1 && words[0].Length != 0)
            {
                switch (words[0])
                {
                    case "A":
                        _FixMode = FixMode.Automatic;
                        break;
                    case "M":
                        _FixMode = FixMode.Manual;
                        break;
                    default:
                        _FixMode = FixMode.Unknown;
                        break;
                }
            }
            else
            {
                _FixMode = FixMode.Unknown;
            }

            #endregion

            #region Fix method

            // Get the fix quality information
            if (wordCount >= 2 && words[1].Length != 0)
            {
                switch (words[1])
                {
                    case "1":
                        _FixMethod = FixMethod.NoFix;
                        break;
                    case "2":
                        _FixMethod = FixMethod.Fix2D;
                        break;
                    case "3":
                        _FixMethod = FixMethod.Fix3D;
                        break;
                    default:
                        _FixMethod = FixMethod.Unknown;
                        break;
                }
            }
            else
            {
                _FixMethod = FixMethod.Unknown;
            }

            #endregion

            #region Fixed satellites

            if (wordCount >= 3)
            {
                // The sentence supports up to 12 satellites
                _FixedSatellites = new List<Satellite>(12);

                // Get each satellite PRN number
                int count = wordCount < 14 ? wordCount : 14;
                for (int index = 2; index < count; index++)
                    // Is the word empty?
                    if (words[index].Length != 0)
                        // No.  Add a satellite
                        _FixedSatellites.Add(
                            // We'll only have an empty object for now
                            new Satellite(int.Parse(words[index], NmeaCultureInfo)));
            }

            #endregion

            #region Dilution of Precision

            // Set overall dilution of precision
            if (wordCount >= 15 && words[14].Length != 0)
                _PositionDop = new DilutionOfPrecision(float.Parse(words[14], NmeaCultureInfo));
            else
                _PositionDop = DilutionOfPrecision.Invalid;

            // Set horizontal dilution of precision
            if (wordCount >= 16 && words[15].Length != 0)
                _HorizontalDop = new DilutionOfPrecision(float.Parse(words[15], NmeaCultureInfo));
            else
                _HorizontalDop = DilutionOfPrecision.Invalid;

            // Set vertical dilution of precision
            if (wordCount >= 17 && words[16].Length != 0)
                _VerticalDop = new DilutionOfPrecision(float.Parse(words[16], NmeaCultureInfo));
            else
                _VerticalDop = DilutionOfPrecision.Invalid;

            #endregion
        }
        protected override void OnSentenceChanged()
        {
            // Parse the basic sentence information
            base.OnSentenceChanged();

            // Cache the words
            string[] words = base.Words;
            int wordCount = words.Length;

            // Do we have enough data to process the UTC time?
            if (wordCount >= 1 && words[0].Length != 0)
            {
                #region UTC Time

                string utcTimeWord = words[0];
                int utcHours = int.Parse(utcTimeWord.Substring(0, 2), NmeaCultureInfo);
                int utcMinutes = int.Parse(utcTimeWord.Substring(2, 2), NmeaCultureInfo);
                int utcSeconds = int.Parse(utcTimeWord.Substring(4, 2), NmeaCultureInfo);
                int utcMilliseconds = 0;
                if(utcTimeWord.Length > 6)
                    utcMilliseconds = Convert.ToInt32(float.Parse(utcTimeWord.Substring(6), NmeaCultureInfo) * 1000, NmeaCultureInfo);

                // Build a TimeSpan for this value
                _UtcTime = new TimeSpan(0, utcHours, utcMinutes, utcSeconds, utcMilliseconds);

                #endregion
            }
            else
            {
                // The UTC time is invalid
                _UtcTime = TimeSpan.MinValue;
            }

            // Do we have enough data for locations?
            if (wordCount >= 5 && words[1].Length != 0 && words[2].Length != 0 && words[3].Length != 0 && words[4].Length != 0)
            {
                #region Latitude

                string latitudeWord = words[1];
                int latitudeHours = int.Parse(latitudeWord.Substring(0, 2), NmeaCultureInfo);
                double latitudeDecimalMinutes = double.Parse(latitudeWord.Substring(2), NmeaCultureInfo);
                LatitudeHemisphere latitudeHemisphere =
                    words[2].Equals("N", StringComparison.OrdinalIgnoreCase) ? LatitudeHemisphere.North : LatitudeHemisphere.South;

                #endregion

                #region Longitude

                string longitudeWord = words[3];
                int longitudeHours = int.Parse(longitudeWord.Substring(0, 3), NmeaCultureInfo);
                double longitudeDecimalMinutes = double.Parse(longitudeWord.Substring(3), NmeaCultureInfo);
                LongitudeHemisphere longitudeHemisphere =
                    words[4].Equals("E", StringComparison.OrdinalIgnoreCase) ? LongitudeHemisphere.East : LongitudeHemisphere.West;

                #endregion

                #region Position

                _Position = new Position(
                                new Latitude(latitudeHours, latitudeDecimalMinutes, latitudeHemisphere),
                                new Longitude(longitudeHours, longitudeDecimalMinutes, longitudeHemisphere));

                #endregion
            }
            else
            {
                _Position = Position.Invalid;
            }

            // Do we have enough data for fix quality?
            if (wordCount >= 6 && words[5].Length != 0)
            {
                #region Fix Quality

                switch (int.Parse(words[5], NmeaCultureInfo))
                {
                    case 0:
                        _FixQuality = FixQuality.NoFix;
                        break;
                    case 1:
                        _FixQuality = FixQuality.GpsFix;
                        break;
                    case 2:
                        _FixQuality = FixQuality.DifferentialGpsFix;
                        break;
                    case 3:
                        _FixQuality = FixQuality.PulsePerSecond;
                        break;
                    case 4:
                        _FixQuality = FixQuality.FixedRealTimeKinematic;
                        break;
                    case 5:
                        _FixQuality = FixQuality.FloatRealTimeKinematic;
                        break;
                    case 6:
                        _FixQuality = FixQuality.Estimated;
                        break;
                    case 7:
                        _FixQuality = FixQuality.ManualInput;
                        break;
                    case 8:
                        _FixQuality = FixQuality.Simulated;
                        break;
                    default:
                        _FixQuality = FixQuality.Unknown;
                        break;
                }

                #endregion
            }
            else
            {
                // This fix quality is invalid
                _FixQuality = FixQuality.Unknown;
            }

            // Number of satellites in view is skipped.  We'll work off of GPGSV data.
            if (wordCount >= 7 && words[6].Length != 0)
            {
                _FixedSatelliteCount = int.Parse(words[6], NmeaCultureInfo);
            }

            // Is there enough information to process horizontal dilution of precision?
            if (wordCount >= 8 && words[7].Length != 0)
            {   
                #region Horizontal Dilution of Precision

                _HorizontalDilutionOfPrecision =
                    new DilutionOfPrecision(float.Parse(words[7], NmeaCultureInfo));
            
                #endregion
            }
            else
            {
                // The HDOP is invalid
                _HorizontalDilutionOfPrecision = DilutionOfPrecision.Invalid;
            }

            // Is there enough information to process altitude?
            if (wordCount >= 9 && words[8].Length != 0)
            {
                #region Altitude

                // Altitude is the 8th NMEA word
                _Altitude = new Distance(float.Parse(words[8], NmeaCultureInfo), DistanceUnit.Meters);

                #endregion
            }
            else
            {
                // The altitude is invalid
                _Altitude = Distance.Invalid;
            }

            // Is there enough information to process geoidal separation?
            if (wordCount >= 11 && words[10].Length != 0)
            {
                #region Geoidal Separation

                // Parse the geoidal separation
                _GeoidalSeparation = new Distance(float.Parse(words[10], NmeaCultureInfo), DistanceUnit.Meters);

                #endregion
            }
            else
            {
                // The geoidal separation is invalid
                _GeoidalSeparation = Distance.Invalid;
            }

            // Is there enough info to process Differential GPS info?
            if (wordCount >= 14 && words[12].Length != 0 && words[13].Length != 0)
            {
                #region Differential GPS information

                if (words[12].Length != 0)
                    _DifferentialGpsAge = TimeSpan.FromSeconds(float.Parse(words[12], NmeaCultureInfo));
                else
                    _DifferentialGpsAge = TimeSpan.MinValue;

                if (words[13].Length != 0)
                    _DifferentialGpsStationID = int.Parse(words[13], NmeaCultureInfo);
                else
                    _DifferentialGpsStationID = -1;

                #endregion
            }
            else
            {
                _DifferentialGpsStationID = -1;
                _DifferentialGpsAge = TimeSpan.MinValue;
            }
        }
        public void Initialize(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Ellipsoid ellipsoid)
        {
            double fail = horizontalDOP.Value * verticalDOP.Value * deviceError.Value;

            if (fail == 0 || double.IsNaN(fail) || double.IsInfinity(fail))
            {
                throw new ArgumentException(
                          "Parameters deviceError, horizontalDOP and verticalDOP must be greater than zero.");
            }

            _currentState = new KalmanSystemState(gpsPosition, deviceError, horizontalDOP, verticalDOP, ellipsoid);
        }
        /// <summary>
        /// Return a filtered Position3D from the specified parameters
        /// </summary>
        /// <param name="gpsPosition">The GPS position.</param>
        /// <param name="deviceError">The device error.</param>
        /// <param name="horizontalDOP">The horizontal DOP.</param>
        /// <param name="verticalDOP">The vertical DOP.</param>
        /// <param name="bearing">The bearing.</param>
        /// <param name="speed">The speed.</param>
        /// <returns></returns>
        public override Position3D Filter(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed)
        {
            double fail = horizontalDOP.Value * verticalDOP.Value * deviceError.Value;
            if (fail == 0 || double.IsNaN(fail) || double.IsInfinity(fail))
            {
                throw new ArgumentException(
                    "Parameters deviceError, horizontalDOP and verticalDOP must be greater than zero.");
            }

            _currentState.UpdateState(deviceError, horizontalDOP, verticalDOP, bearing, speed, gpsPosition);
            return _currentState.CorrectedLocation();
        }
 public Position Filter(Position gpsPosition, DilutionOfPrecision currentDOP)
 {
     return(Filter(gpsPosition, _currentState.DeviceError, currentDOP, currentDOP, Azimuth.Empty, Speed.AtRest));
 }
        /// <summary>
        /// Updates the state.
        /// </summary>
        /// <param name="deviceError">The device error.</param>
        /// <param name="horizontalDOP">The horizontal DOP.</param>
        /// <param name="verticalDOP">The vertical DOP.</param>
        /// <param name="bearing">The bearing.</param>
        /// <param name="speed">The speed.</param>
        /// <param name="z">The z.</param>
        public void UpdateState(Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed, Position3D z)
        {
            if (_x.IsInvalid)
            {
                Initialize(z);
                return;
            }

            // More insanity
            double fail = horizontalDOP.Value * verticalDOP.Value * deviceError.Value;
            if (fail == 0 || double.IsNaN(fail) || double.IsInfinity(fail))
            {
                throw new ArgumentException(
                    "Covariance values are invalid. Parameters deviceError, horizontalDOP and verticalDOP must be greater than zero.");
            }

            _deviceError = deviceError.Value;
            _horizontalDOP = horizontalDOP.Value;
            _verticalDOP = verticalDOP.Value;

            double hCovariance = _deviceError * _horizontalDOP;
            double vCovariance = _deviceError * _verticalDOP;

            // Setup the observation covariance (measurement error)
            _r = new SquareMatrix3D(
                hCovariance, 0, 0,
                0, hCovariance, 0,
                0, 0, vCovariance);

            #region Process Noise Estimation

            // Get the translation of the last correction
            CartesianPoint subX = _x.ToPosition3D(_ellipsoid)
                .TranslateTo(bearing, speed.ToDistance(_delay), _ellipsoid)
                .ToCartesianPoint();

            // Get the vector of the translation and the last observation
            //CartesianPoint w = (subX - this.z);
            CartesianPoint w =
                new CartesianPoint(
                    Distance.FromMeters(subX.X.Value - _z.X.Value),   // Values are in meters
                    Distance.FromMeters(subX.Y.Value - _z.Y.Value),   // Values are in meters
                    Distance.FromMeters(subX.Z.Value - _z.Z.Value));  // Values are in meters

            // Setup the noise covariance (process error)
            _q = new SquareMatrix3D(
                Math.Abs(w.X.Value), 0, 0,
                0, Math.Abs(w.Y.Value), 0,
                0, 0, Math.Abs(w.Z.Value));

            #endregion Process Noise Estimation

            // Update the observation state
            _z = z.ToCartesianPoint(_ellipsoid);

            #region State vector prediction and covariance

            //s.x = s.A*s.x + s.B*s.u;
            //this.x = this.A * this.x + this.B * this.u;
            CartesianPoint ax = _a.TransformVector(_x);
            CartesianPoint bu = _b.TransformVector(_u);
            _x =
                new CartesianPoint(
                    Distance.FromMeters(ax.X.Value + bu.X.Value),
                    Distance.FromMeters(ax.Y.Value + bu.Y.Value),
                    Distance.FromMeters(ax.Z.Value + bu.Z.Value));

            //s.P = s.A * s.P * s.A' + s.Q;
            _p = _a * _p * SquareMatrix3D.Transpose(_a) + _q;

            #endregion State vector prediction and covariance

            #region Kalman gain factor

            //K = s.P*s.H'*inv(s.H*s.P*s.H'+s.R);
            SquareMatrix3D ht = SquareMatrix3D.Transpose(_h);
            SquareMatrix3D k = _p * ht * SquareMatrix3D.Invert(_h * _p * ht + _r);

            #endregion Kalman gain factor

            #region Observational correction

            //s.x = s.x + K*(s.z-s.H*s.x);
            //this.x = this.x + K * (this.z - this.H * this.x);
            CartesianPoint hx = _h.TransformVector(_x);
            CartesianPoint zHx = new CartesianPoint(
                Distance.FromMeters(_z.X.Value - hx.X.Value),
                Distance.FromMeters(_z.Y.Value - hx.Y.Value),
                Distance.FromMeters(_z.Z.Value - hx.Z.Value));
            CartesianPoint kzHx = k.TransformVector(zHx);
            _x =
                new CartesianPoint(
                    Distance.FromMeters(_x.X.Value + kzHx.X.Value),
                    Distance.FromMeters(_x.Y.Value + kzHx.Y.Value),
                    Distance.FromMeters(_x.Z.Value + kzHx.Z.Value));

            //s.P = s.P - K*s.H*s.P;
            _p = _p - k * _h * _p;

            #endregion Observational correction

            // Bump the state count
            _interval++;

            // Calculate the average error for the system stste.
            _errorState = (_errorState + Math.Sqrt(Math.Pow(hCovariance, 2) + Math.Pow(vCovariance, 2))) * .5f;

            // Calculate the interval between samples
            DateTime now = DateTime.Now;
            _delay = now.Subtract(_lastObservation);
            _lastObservation = now;
        }
        public override Position Filter(Position gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed)
        {
            Position3D pos3d = Filter(new Position3D(gpsPosition), deviceError, horizontalDOP, verticalDOP, bearing, speed);

            return(new Position(pos3d.Latitude, pos3d.Longitude));
        }
 /// <summary>
 /// Initializes the Kalman Filter using an initial observation (position)
 /// </summary>
 /// <param name="gpsPosition">The position at which tfilter is to begin opperating.</param>
 /// <param name="meanDOP">The mean dilution of precision</param>
 public void Initialize(Position3D gpsPosition, DilutionOfPrecision meanDOP)
 {
     Initialize(gpsPosition, DilutionOfPrecision.CurrentAverageDevicePrecision, meanDOP, meanDOP, Ellipsoid.Default);
 }
 public Position3D Filter(Position3D gpsPosition, DilutionOfPrecision currentDOP, Azimuth bearing, Speed speed)
 {
     return(Filter(gpsPosition, _currentState.DeviceError, currentDOP, currentDOP, bearing, Speed.AtRest));
 }
 /// <summary>
 /// Returns the position
 /// </summary>
 /// <param name="gpsPosition">The gps Position</param>
 /// <param name="currentDOP">The current dilution of precision</param>
 /// <param name="bearing">the directional azimuth</param>
 /// <param name="speed">the magnitude of the velocity</param>
 /// <returns>A Position sturcture</returns>
 public Position Filter(Position gpsPosition, DilutionOfPrecision currentDOP, Azimuth bearing, Speed speed)
 {
     return Filter(gpsPosition, _currentState.DeviceError, currentDOP, currentDOP, bearing, speed);
 }
        public override Position3D Filter(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed)
        {
            double fail = horizontalDOP.Value * verticalDOP.Value * deviceError.Value;

            if (fail == 0 || double.IsNaN(fail) || double.IsInfinity(fail))
            {
                throw new ArgumentException(
                          "Parameters deviceError, horizontalDOP and verticalDOP must be greater than zero.");
            }

            _currentState.UpdateState(deviceError, horizontalDOP, verticalDOP, bearing, speed, gpsPosition);
            return(_currentState.CorrectedLocation());
        }
        /// <summary>
        /// Adds a new observation and applies the filter.
        /// </summary>
        /// <param name="gpsPosition"> The new observation to add to the filter. </param>
        /// <param name="deviceError"> Does not currently affect position averaging. </param>
        /// <param name="horizontalDOP"> Does not currently affect position averaging. </param>
        /// <param name="verticalDOP"> Does not currently affect position averaging. </param>
        /// <param name="bearing"> Does not currently affect position averaging. </param>
        /// <param name="speed"> Does not currently affect position averaging. </param>
        /// <remarks>
        /// This method updates the FilteredLocation property without consideration for SampleCount.
        /// </remarks>
        public override Position3D Filter(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed)
        {
            this._samples.Add(gpsPosition);
            this._sampleTimes.Add(DateTime.Now);

            int count     = this._samples.Count;
            int timeCount = this._sampleTimes.Count;
            int maxCount  = 0;

            // Only average the number of samples specified in the constructor
            while (count > _sampleCount)
            {
                this._samples.RemoveAt(0);
                count--;
                maxCount++;
            }

            // Only 2 times are needed, oldest and most recent.
            // Try to remove as many as were removed from the sample collection.
            while (timeCount > 2 && maxCount > 0)
            {
                this._sampleTimes.RemoveAt(0);
                timeCount--;
            }

            Filter();

            return(_filteredPositon);
        }
Exemple #27
0
        protected override void OnSentenceChanged()
        {
            // First, process the basic info for the sentence
            base.OnSentenceChanged();

            // Cache the sentence words
            string[] words     = base.Words;
            int      wordCount = words.Length;

            #region Fix mode

            if (wordCount >= 1 && words[0].Length != 0)
            {
                switch (words[0])
                {
                case "A":
                    _FixMode = FixMode.Automatic;
                    break;

                case "M":
                    _FixMode = FixMode.Manual;
                    break;

                default:
                    _FixMode = FixMode.Unknown;
                    break;
                }
            }
            else
            {
                _FixMode = FixMode.Unknown;
            }

            #endregion

            #region Fix method

            // Get the fix quality information
            if (wordCount >= 2 && words[1].Length != 0)
            {
                switch (words[1])
                {
                case "1":
                    _FixMethod = FixMethod.NoFix;
                    break;

                case "2":
                    _FixMethod = FixMethod.Fix2D;
                    break;

                case "3":
                    _FixMethod = FixMethod.Fix3D;
                    break;

                default:
                    _FixMethod = FixMethod.Unknown;
                    break;
                }
            }
            else
            {
                _FixMethod = FixMethod.Unknown;
            }

            #endregion

            #region Fixed satellites

            if (wordCount >= 3)
            {
                // The sentence supports up to 12 satellites
                _FixedSatellites = new List <Satellite>(12);

                // Get each satellite PRN number
                int count = wordCount < 14 ? wordCount : 14;
                for (int index = 2; index < count; index++)
                {
                    // Is the word empty?
                    if (words[index].Length != 0)
                    {
                        // No.  Add a satellite
                        _FixedSatellites.Add(
                            // We'll only have an empty object for now
                            new Satellite(int.Parse(words[index], NmeaCultureInfo)));
                    }
                }
            }

            #endregion

            #region Dilution of Precision

            // Set overall dilution of precision
            if (wordCount >= 15 && words[14].Length != 0)
            {
                _PositionDop = new DilutionOfPrecision(float.Parse(words[14], NmeaCultureInfo));
            }
            else
            {
                _PositionDop = DilutionOfPrecision.Invalid;
            }

            // Set horizontal dilution of precision
            if (wordCount >= 16 && words[15].Length != 0)
            {
                _HorizontalDop = new DilutionOfPrecision(float.Parse(words[15], NmeaCultureInfo));
            }
            else
            {
                _HorizontalDop = DilutionOfPrecision.Invalid;
            }

            // Set vertical dilution of precision
            if (wordCount >= 17 && words[16].Length != 0)
            {
                _VerticalDop = new DilutionOfPrecision(float.Parse(words[16], NmeaCultureInfo));
            }
            else
            {
                _VerticalDop = DilutionOfPrecision.Invalid;
            }

            #endregion
        }
        public void Randomize(
            DilutionOfPrecision minHDOP,
            DilutionOfPrecision maxHDOP,
            DilutionOfPrecision minVDOP,
            DilutionOfPrecision maxVDOP)
        {
            _minHDOP = minHDOP.Value;
            _maxHDOP = maxHDOP.Value;
            _minVDOP = minVDOP.Value;
            _maxVDOP = maxVDOP.Value;

            SetRandom(true);
        }
Exemple #29
0
        public GpgsaSentence(FixMode fixMode, FixMethod fixMethod, IList <Satellite> satellites,
                             DilutionOfPrecision positionDilutionOfPrecision,
                             DilutionOfPrecision horizontalDilutionOfPrecision,
                             DilutionOfPrecision verticalDilutionOfPrecision)
        {
            // Use a string builder to create the sentence text
            StringBuilder builder = new StringBuilder(128);

            // Append the command word
            builder.Append("$GPGSA");

            // Append a comma
            builder.Append(',');

            #region Append the fix method

            switch (_FixMode)
            {
            case FixMode.Automatic:
                builder.Append("A");
                break;

            default:
                builder.Append("M");
                break;
            }

            #endregion

            // Append a comma
            builder.Append(',');

            #region Append the fix method

            switch (_FixMethod)
            {
            case FixMethod.Fix2D:
                builder.Append("2");
                break;

            case FixMethod.Fix3D:
                builder.Append("3");
                break;

            default:
                builder.Append("1");
                break;
            }

            #endregion

            // Append a comma
            builder.Append(',');

            #region Fixed satellites

            /* A comma-delimited list of satellites involved in a fix.  Up to 12 satellites can be serialized.
             * This one concerns me, because while the limit is 12, ever more satellites are being launched.
             * Should we just serialize everything??
             */

            // Get a count of satellites to write, up to 123.  We'll scrub the list to ensure only fixed satellites are written
            int fixedSatellitesWritten = 0;
            for (int index = 0; index < satellites.Count; index++)
            {
                // Get the satellite
                Satellite item = satellites[index];

                // Is it fixed?
                if (item.IsFixed)
                {
                    // Yes.  It cannot have babies
                    builder.Append(item.PseudorandomNumber.ToString(NmeaCultureInfo));

                    // Append a comma
                    builder.Append(",");

                    // Update the count
                    fixedSatellitesWritten++;

                    // If we're at 12, that's the limit.  Stop here
                    if (fixedSatellitesWritten == 12)
                    {
                        break;
                    }
                }
            }

            // If we wrote less than 12 satellites, write commas for the remainder
            for (int index = 0; index < 12 - fixedSatellitesWritten; index++)
            {
                builder.Append(",");
            }

            #endregion

            // NOTE: Commas have been written at this point

            // Position Dilution of Precision
            builder.Append(positionDilutionOfPrecision.Value.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",");

            // Horizontal Dilution of Precision
            builder.Append(horizontalDilutionOfPrecision.Value.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",");

            // Vertical Dilution of Precision
            builder.Append(verticalDilutionOfPrecision.Value.ToString(NmeaCultureInfo));

            // Set this object's sentence
            SetSentence(builder.ToString());

            // Finally, append the checksum
            AppendChecksum();
        }
Exemple #30
0
        protected override void OnSentenceChanged()
        {
            // Parse the basic sentence information
            base.OnSentenceChanged();

            // Cache the words
            string[] words     = base.Words;
            int      wordCount = words.Length;

            // Do we have enough data to process the UTC time?
            if (wordCount >= 1 && words[0].Length != 0)
            {
                #region UTC Time

                string utcTimeWord     = words[0];
                int    utcHours        = int.Parse(utcTimeWord.Substring(0, 2), NmeaCultureInfo);
                int    utcMinutes      = int.Parse(utcTimeWord.Substring(2, 2), NmeaCultureInfo);
                int    utcSeconds      = int.Parse(utcTimeWord.Substring(4, 2), NmeaCultureInfo);
                int    utcMilliseconds = 0;
                if (utcTimeWord.Length > 6)
                {
                    utcMilliseconds = Convert.ToInt32(float.Parse(utcTimeWord.Substring(6), NmeaCultureInfo) * 1000, NmeaCultureInfo);
                }

                // Build a TimeSpan for this value
                _UtcTime = new TimeSpan(0, utcHours, utcMinutes, utcSeconds, utcMilliseconds);

                #endregion
            }
            else
            {
                // The UTC time is invalid
                _UtcTime = TimeSpan.MinValue;
            }

            // Do we have enough data for locations?
            if (wordCount >= 5 && words[1].Length != 0 && words[2].Length != 0 && words[3].Length != 0 && words[4].Length != 0)
            {
                #region Latitude

                string             latitudeWord           = words[1];
                int                latitudeHours          = int.Parse(latitudeWord.Substring(0, 2), NmeaCultureInfo);
                double             latitudeDecimalMinutes = double.Parse(latitudeWord.Substring(2), NmeaCultureInfo);
                LatitudeHemisphere latitudeHemisphere     =
                    words[2].Equals("N", StringComparison.OrdinalIgnoreCase) ? LatitudeHemisphere.North : LatitudeHemisphere.South;

                #endregion

                #region Longitude

                string longitudeWord                    = words[3];
                int    longitudeHours                   = int.Parse(longitudeWord.Substring(0, 3), NmeaCultureInfo);
                double longitudeDecimalMinutes          = double.Parse(longitudeWord.Substring(3), NmeaCultureInfo);
                LongitudeHemisphere longitudeHemisphere =
                    words[4].Equals("E", StringComparison.OrdinalIgnoreCase) ? LongitudeHemisphere.East : LongitudeHemisphere.West;

                #endregion

                #region Position

                _Position = new Position(
                    new Latitude(latitudeHours, latitudeDecimalMinutes, latitudeHemisphere),
                    new Longitude(longitudeHours, longitudeDecimalMinutes, longitudeHemisphere));

                #endregion
            }
            else
            {
                _Position = Position.Invalid;
            }

            // Do we have enough data for fix quality?
            if (wordCount >= 6 && words[5].Length != 0)
            {
                #region Fix Quality

                switch (int.Parse(words[5], NmeaCultureInfo))
                {
                case 0:
                    _FixQuality = FixQuality.NoFix;
                    break;

                case 1:
                    _FixQuality = FixQuality.GpsFix;
                    break;

                case 2:
                    _FixQuality = FixQuality.DifferentialGpsFix;
                    break;

                case 3:
                    _FixQuality = FixQuality.PulsePerSecond;
                    break;

                case 4:
                    _FixQuality = FixQuality.FixedRealTimeKinematic;
                    break;

                case 5:
                    _FixQuality = FixQuality.FloatRealTimeKinematic;
                    break;

                case 6:
                    _FixQuality = FixQuality.Estimated;
                    break;

                case 7:
                    _FixQuality = FixQuality.ManualInput;
                    break;

                case 8:
                    _FixQuality = FixQuality.Simulated;
                    break;

                default:
                    _FixQuality = FixQuality.Unknown;
                    break;
                }

                #endregion
            }
            else
            {
                // This fix quality is invalid
                _FixQuality = FixQuality.Unknown;
            }

            // Number of satellites in view is skipped.  We'll work off of GPGSV data.
            if (wordCount >= 7 && words[6].Length != 0)
            {
                _FixedSatelliteCount = int.Parse(words[6], NmeaCultureInfo);
            }

            // Is there enough information to process horizontal dilution of precision?
            if (wordCount >= 8 && words[7].Length != 0)
            {
                #region Horizontal Dilution of Precision

                _HorizontalDilutionOfPrecision =
                    new DilutionOfPrecision(float.Parse(words[7], NmeaCultureInfo));

                #endregion
            }
            else
            {
                // The HDOP is invalid
                _HorizontalDilutionOfPrecision = DilutionOfPrecision.Invalid;
            }

            // Is there enough information to process altitude?
            if (wordCount >= 9 && words[8].Length != 0)
            {
                #region Altitude

                // Altitude is the 8th NMEA word
                _Altitude = new Distance(float.Parse(words[8], NmeaCultureInfo), DistanceUnit.Meters);

                #endregion
            }
            else
            {
                // The altitude is invalid
                _Altitude = Distance.Invalid;
            }

            // Is there enough information to process geoidal separation?
            if (wordCount >= 11 && words[10].Length != 0)
            {
                #region Geoidal Separation

                // Parse the geoidal separation
                _GeoidalSeparation = new Distance(float.Parse(words[10], NmeaCultureInfo), DistanceUnit.Meters);

                #endregion
            }
            else
            {
                // The geoidal separation is invalid
                _GeoidalSeparation = Distance.Invalid;
            }

            // Is there enough info to process Differential GPS info?
            if (wordCount >= 14 && words[12].Length != 0 && words[13].Length != 0)
            {
                #region Differential GPS information

                if (words[12].Length != 0)
                {
                    _DifferentialGpsAge = TimeSpan.FromSeconds(float.Parse(words[12], NmeaCultureInfo));
                }
                else
                {
                    _DifferentialGpsAge = TimeSpan.MinValue;
                }

                if (words[13].Length != 0)
                {
                    _DifferentialGpsStationID = int.Parse(words[13], NmeaCultureInfo);
                }
                else
                {
                    _DifferentialGpsStationID = -1;
                }

                #endregion
            }
            else
            {
                _DifferentialGpsStationID = -1;
                _DifferentialGpsAge       = TimeSpan.MinValue;
            }
        }
Exemple #31
0
        public GpggaSentence(TimeSpan utcTime, Position position, FixQuality fixQuality, int trackedSatelliteCount,
                             DilutionOfPrecision horizontalDilutionOfPrecision, Distance altitude, Distance geoidalSeparation,
                             TimeSpan differentialGpsAge, int differentialGpsStationID)
        {
            // Use a string builder to create the sentence text
            StringBuilder builder = new StringBuilder(128);

            #region Append the command word

            // Append the command word
            builder.Append("$GPGGA");

            #endregion

            // Append a comma
            builder.Append(',');

            #region Append the UTC time

            /* Convert UTC time to a string in the form HHMMSS.SSSS. Any value less than 10 will be
             * padded with a zero.
             */

            builder.Append(_UtcTime.Hours.ToString("0#", NmeaCultureInfo));
            builder.Append(_UtcTime.Minutes.ToString("0#", NmeaCultureInfo));
            builder.Append(_UtcTime.Seconds.ToString("0#", NmeaCultureInfo));
            builder.Append(".");
            builder.Append(_UtcTime.Milliseconds.ToString("00#", NmeaCultureInfo));

            #endregion

            // Append a comma
            builder.Append(',');

            #region Append the position

            // Append latitude in the format HHMM.MMMM.
            builder.Append(position.Latitude.ToString("HHMM.MMMM,I,", NmeaCultureInfo));
            // Append Longitude in the format HHHMM.MMMM.
            builder.Append(position.Longitude.ToString("HHHMM.MMMM,I,", NmeaCultureInfo));

            #endregion

            #region Append fix quality

            switch (fixQuality)
            {
            case FixQuality.NoFix:
                builder.Append("0");
                break;

            case FixQuality.GpsFix:
                builder.Append("1");
                break;

            case FixQuality.DifferentialGpsFix:
                builder.Append("2");
                break;

            case FixQuality.PulsePerSecond:
                builder.Append("3");
                break;

            case FixQuality.FixedRealTimeKinematic:
                builder.Append("4");
                break;

            case FixQuality.FloatRealTimeKinematic:
                builder.Append("5");
                break;

            case FixQuality.Estimated:
                builder.Append("6");
                break;

            case FixQuality.ManualInput:
                builder.Append("7");
                break;

            case FixQuality.Simulated:
                builder.Append("8");
                break;
            }

            #endregion

            // Append a comma
            builder.Append(",");

            // Append the tracked (signal strength is > 0) satellite count
            builder.Append(trackedSatelliteCount.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",");

            // Append the numerical value of HDOP
            builder.Append(horizontalDilutionOfPrecision.Value.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",");

            #region Altitude above sea level

            // Append the numerical value in meters
            builder.Append(altitude.ToMeters().Value.ToString(NmeaCultureInfo));

            // Append a comma, the unit (M = meters), and another comma
            builder.Append(",M,");

            #endregion

            #region Geoidal separation

            // Append the numerical value in meters
            builder.Append(geoidalSeparation.ToMeters().Value.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",M,");

            #endregion

            #region Differential GPS information

            // Differnetial signal age in seconds
            if (!differentialGpsAge.Equals(TimeSpan.MinValue))
            {
                builder.Append(differentialGpsAge.TotalSeconds.ToString(NmeaCultureInfo));
            }

            // Append a comma
            builder.Append(",");

            // Station ID
            if (differentialGpsStationID != -1)
            {
                builder.Append(differentialGpsStationID.ToString(NmeaCultureInfo));
            }

            #endregion

            // Set this object's sentence
            SetSentence(builder.ToString());

            // Finally, append the checksum
            AppendChecksum();
        }
        public GpgsaSentence(FixMode fixMode, FixMethod fixMethod, IList<Satellite> satellites,
            DilutionOfPrecision positionDilutionOfPrecision,
            DilutionOfPrecision horizontalDilutionOfPrecision,
            DilutionOfPrecision verticalDilutionOfPrecision)
        {
            // Use a string builder to create the sentence text
            StringBuilder builder = new StringBuilder(128);

            // Append the command word
            builder.Append("$GPGSA");

            // Append a comma
            builder.Append(',');

            #region Append the fix method

            switch (_FixMode)
            {
                case FixMode.Automatic:
                    builder.Append("A");
                    break;
                default:
                    builder.Append("M");
                    break;
            }

            #endregion

            // Append a comma
            builder.Append(',');
        
            #region Append the fix method

            switch (_FixMethod)
            {
                case FixMethod.Fix2D:
                    builder.Append("2");
                    break;
                case FixMethod.Fix3D:
                    builder.Append("3");
                    break;
                default:
                    builder.Append("1");
                    break;
            }

            #endregion

            // Append a comma
            builder.Append(',');

            #region Fixed satellites

            /* A comma-delimited list of satellites involved in a fix.  Up to 12 satellites can be serialized.
             * This one concerns me, because while the limit is 12, ever more satellites are being launched.
             * Should we just serialize everything??
             */

            // Get a count of satellites to write, up to 123.  We'll scrub the list to ensure only fixed satellites are written
            int fixedSatellitesWritten = 0;
            for(int index = 0; index < satellites.Count; index++)
            {
                // Get the satellite
                Satellite item = satellites[index];

                // Is it fixed?
                if(item.IsFixed)
                {
                    // Yes.  It cannot have babies
                    builder.Append(item.PseudorandomNumber.ToString(NmeaCultureInfo));

                    // Append a comma
                    builder.Append(",");

                    // Update the count
                    fixedSatellitesWritten++;

                    // If we're at 12, that's the limit.  Stop here
                    if(fixedSatellitesWritten == 12)
                        break;
                }
            }

            // If we wrote less than 12 satellites, write commas for the remainder
            for(int index = 0; index < 12 - fixedSatellitesWritten; index++)
                builder.Append(",");

            #endregion

            // NOTE: Commas have been written at this point

            // Position Dilution of Precision
            builder.Append(positionDilutionOfPrecision.Value.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",");

            // Horizontal Dilution of Precision
            builder.Append(horizontalDilutionOfPrecision.Value.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",");

            // Vertical Dilution of Precision
            builder.Append(verticalDilutionOfPrecision.Value.ToString(NmeaCultureInfo));

            // Set this object's sentence
            SetSentence(builder.ToString());

            // Finally, append the checksum
            AppendChecksum();
        }
 public abstract Position3D Filter(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed);
        public GpggaSentence(TimeSpan utcTime, Position position, FixQuality fixQuality, int trackedSatelliteCount,
                            DilutionOfPrecision horizontalDilutionOfPrecision, Distance altitude, Distance geoidalSeparation,
                            TimeSpan differentialGpsAge, int differentialGpsStationID)
        {        
            // Use a string builder to create the sentence text
            StringBuilder builder = new StringBuilder(128);

            #region Append the command word

            // Append the command word
            builder.Append("$GPGGA");

            #endregion

            // Append a comma
            builder.Append(',');

            #region Append the UTC time

            /* Convert UTC time to a string in the form HHMMSS.SSSS. Any value less than 10 will be
             * padded with a zero.
             */

            builder.Append(_UtcTime.Hours.ToString("0#", NmeaCultureInfo));
            builder.Append(_UtcTime.Minutes.ToString("0#", NmeaCultureInfo));
            builder.Append(_UtcTime.Seconds.ToString("0#", NmeaCultureInfo));
            builder.Append(".");
            builder.Append(_UtcTime.Milliseconds.ToString("00#", NmeaCultureInfo));

            #endregion

            // Append a comma
            builder.Append(',');

            #region Append the position

            // Append latitude in the format HHMM.MMMM. 
            builder.Append(position.Latitude.ToString("HHMM.MMMM,I,", NmeaCultureInfo));
            // Append Longitude in the format HHHMM.MMMM.
            builder.Append(position.Longitude.ToString("HHHMM.MMMM,I,", NmeaCultureInfo));

            #endregion

            #region Append fix quality

            switch (fixQuality)
            {
                case FixQuality.NoFix:
                    builder.Append("0");
                    break;
                case FixQuality.GpsFix:
                    builder.Append("1");
                    break;
                case FixQuality.DifferentialGpsFix:
                    builder.Append("2");
                    break;
                case FixQuality.PulsePerSecond:
                    builder.Append("3");
                    break;
                case FixQuality.FixedRealTimeKinematic:
                    builder.Append("4");
                    break;
                case FixQuality.FloatRealTimeKinematic:
                    builder.Append("5");
                    break;
                case FixQuality.Estimated:
                    builder.Append("6");
                    break;
                case FixQuality.ManualInput:
                    builder.Append("7");
                    break;
                case FixQuality.Simulated:
                    builder.Append("8");
                    break;              
            }

            #endregion

            // Append a comma
            builder.Append(",");

            // Append the tracked (signal strength is > 0) satellite count
            builder.Append(trackedSatelliteCount.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",");

            // Append the numerical value of HDOP
            builder.Append(horizontalDilutionOfPrecision.Value.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",");

            #region Altitude above sea level

            // Append the numerical value in meters
            builder.Append(altitude.ToMeters().Value.ToString(NmeaCultureInfo));

            // Append a comma, the unit (M = meters), and another comma
            builder.Append(",M,"); 

            #endregion

            #region Geoidal separation

            // Append the numerical value in meters
            builder.Append(geoidalSeparation.ToMeters().Value.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",M,");

            #endregion

            #region Differential GPS information

            // Differnetial signal age in seconds
            if (!differentialGpsAge.Equals(TimeSpan.MinValue))
                builder.Append(differentialGpsAge.TotalSeconds.ToString(NmeaCultureInfo));

            // Append a comma
            builder.Append(",");

            // Station ID
            if (differentialGpsStationID != -1)
                builder.Append(differentialGpsStationID.ToString(NmeaCultureInfo));

            #endregion

            // Set this object's sentence
            SetSentence(builder.ToString());

            // Finally, append the checksum
            AppendChecksum();
        }
Exemple #35
0
        protected override void OnSentenceChanged()
        {
            // Process the basic sentence elements
            base.OnSentenceChanged();

            // Cache the word array
            string[] words     = base.Words;
            int      wordCount = words.Length;

            // Do we have enough words to parse the UTC date/time?
            if (wordCount >= 2 && words[0].Length != 0 && words[1].Length != 0)
            {
                #region Parse the UTC time

                string utcTimeWord     = words[0];
                int    utcHours        = int.Parse(utcTimeWord.Substring(0, 2), NmeaCultureInfo);
                int    utcMinutes      = int.Parse(utcTimeWord.Substring(2, 2), NmeaCultureInfo);
                int    utcSeconds      = int.Parse(utcTimeWord.Substring(4, 2), NmeaCultureInfo);
                int    utcMilliseconds = Convert.ToInt32(float.Parse(utcTimeWord.Substring(6), NmeaCultureInfo) * 1000, NmeaCultureInfo);

                #endregion

                #region Parse the UTC date

                string utcDateWord = words[1];
                int    utcMonth    = int.Parse(utcDateWord.Substring(0, 2), NmeaCultureInfo);
                int    utcDay      = int.Parse(utcDateWord.Substring(2, 2), NmeaCultureInfo);
                int    utcYear     = int.Parse(utcDateWord.Substring(4, 2), NmeaCultureInfo) + 2000;

                #endregion

                #region Build a UTC date/time

                _UtcDateTime = new DateTime(utcYear, utcMonth, utcDay, utcHours, utcMinutes, utcSeconds, utcMilliseconds, DateTimeKind.Utc);

                #endregion
            }
            else
            {
                // The UTC date/time is invalid
                _UtcDateTime = DateTime.MinValue;
            }

            // Do we have enough data to parse the location?
            if (wordCount >= 6 && words[2].Length != 0 && words[3].Length != 0 && words[4].Length != 0 && words[5].Length != 0)
            {
                #region Parse the latitude

                string             latitudeWord           = words[2];
                int                latitudeHours          = int.Parse(latitudeWord.Substring(0, 2), NmeaCultureInfo);
                double             latitudeDecimalMinutes = double.Parse(latitudeWord.Substring(2), NmeaCultureInfo);
                LatitudeHemisphere latitudeHemisphere     =
                    words[3].Equals("N", StringComparison.OrdinalIgnoreCase) ? LatitudeHemisphere.North : LatitudeHemisphere.South;

                #endregion

                #region Parse the longitude

                string longitudeWord                    = words[4];
                int    longitudeHours                   = int.Parse(longitudeWord.Substring(0, 3), NmeaCultureInfo);
                double longitudeDecimalMinutes          = double.Parse(longitudeWord.Substring(3), NmeaCultureInfo);
                LongitudeHemisphere longitudeHemisphere =
                    words[5].Equals("E", StringComparison.OrdinalIgnoreCase) ? LongitudeHemisphere.East : LongitudeHemisphere.West;

                #endregion

                #region Build a Position from the latitude and longitude

                _Position = new Position(
                    new Latitude(latitudeHours, latitudeDecimalMinutes, latitudeHemisphere),
                    new Longitude(longitudeHours, longitudeDecimalMinutes, longitudeHemisphere));

                #endregion
            }

            // Do we have enough data for the fix quality?
            if (wordCount > 7 && words[7].Length != 0)
            {
                switch (Convert.ToInt32(words[7], NmeaCultureInfo))
                {
                case 0:
                    _FixQuality = FixQuality.NoFix;
                    break;

                case 1:
                    _FixQuality = FixQuality.GpsFix;
                    break;

                case 2:
                    _FixQuality = FixQuality.DifferentialGpsFix;
                    break;

                case 3:
                    _FixQuality = FixQuality.PulsePerSecond;
                    break;

                case 4:
                    _FixQuality = FixQuality.FixedRealTimeKinematic;
                    break;

                case 5:
                    _FixQuality = FixQuality.FloatRealTimeKinematic;
                    break;

                case 6:
                    _FixQuality = FixQuality.Estimated;
                    break;

                case 7:
                    _FixQuality = FixQuality.ManualInput;
                    break;

                case 8:
                    _FixQuality = FixQuality.Simulated;
                    break;

                default:
                    _FixQuality = FixQuality.Unknown;
                    break;
                }
            }
            else
            {
                // The fix quality is invalid
                _FixQuality = FixQuality.Unknown;
            }

            // Process the fixed satellite count
            if (wordCount > 8)
            {
                _FixedSatelliteCount = int.Parse(Words[8], NmeaCultureInfo);
            }
            else
            {
                _FixedSatelliteCount = 0;
            }

            // Process the mean DOP
            if (wordCount > 9 && Words[9].Length != 0)
            {
                _MeanDilutionOfPrecision = new DilutionOfPrecision(float.Parse(Words[9], NmeaCultureInfo));
            }
            else
            {
                _MeanDilutionOfPrecision = DilutionOfPrecision.Maximum;
            }

            // Altitude above ellipsoid
            if (wordCount > 10 && Words[10].Length != 0)
            {
                _AltitudeAboveEllipsoid = new Distance(double.Parse(Words[10], NmeaCultureInfo), DistanceUnit.Meters).ToLocalUnitType();
            }
            else
            {
                _AltitudeAboveEllipsoid = Distance.Empty;
            }
        }
        /// <summary>
        /// OnSentanceChanged event handler
        /// </summary>
        protected override void OnSentenceChanged()
        {
            base.OnSentenceChanged();

            // Cache the sentence words
            string[] words = Words;
            int wordCount = words.Length;

            /*
             *  Garmin produces several embedded GPS systems. They are easy to setup because Garmin provides a nice utility for uploading configuration data to the GPS. You first load the utility to a PC. Connect the PC to the GPS through one of the serial ports. The utility will check each baud rate until it communicates with the GPS.

                The common configuration parameters are output sentences from the GPS unit, the communication baud rate with a host, and the required pulse per second.

                Each sentence is preceded with a ‘$’ symbol and ends with a line-feed character. At one sentence per second, the following is out put in four seconds:

                $PGRMF, 223, 424798, 041203, 215945, 13, 0000.0000, N, 00000.0000, W, A, 2, 0, 62, 2, 1*3B
                $PGRMF, 223, 424799, 041203, 215946, 13, 00000.0000, N, 00000.0000, W, A, 2, 0, 62, 2, 1*39
                $PGRMF, 223, 424800, 041203, 215947, 13, 00000.0000, N, 00000.0000, W, A, 2, 0, 62, 2, 1*34
                $PGRMF, 223, 424801, 041203, 215948, 13, 00000.0000, N, 00000.0000, W, A, 2, 0, 62, 2, 1*35

                The sentence is proprietary to the Garmin GPS Global Positioning System and is translated below.

                $PGRMF
                <1>GPS Week Number(0-1023)
                <2>GPS Seconds (0 - 604799)
                <3>UTC Date of position fix, ddmmyy format
                <4>UTC time of position fix, hhmmss format
                <5>GPS leap second count
                <6>Latitude, ddmm.mmmm format (leading zeros transmitted)
                <7>Latitude hemisphere N or S
                <8>Longitude, ddmm.mmmm format (leading zeros transmitted)
                <9>Longitude hemisphere N or S
                <10>Mode M = Manual, A automatic
                <11>Fix type 0 = No Fix, 1 = 2D Fix, 2 = 3D fix
                <12>Speed over ground, 0 to 359 degrees true
                <13>Course over ground, 0 to 9 (rounded to nearest intvalue)
                <14>Time dilution of precision, 0 to 9 (rnded nearest int val)
                <15>Time dilution of precision, 0 to 9 (rnded nearest int val)
                *hh <CR><LF>
             */

            // TODO: Convert GPS week number/seconds to UTC date/time

            // Do we have enough words to parse the fix status?
            if (wordCount >= 4 && words[2].Length != 0 && words[3].Length != 0)
            {
                // Build a UTC date/time object.
                _utcDateTime = new DateTime(
                    int.Parse(words[2].Substring(4, 2), NmeaCultureInfo) + 2000, // Year
                    int.Parse(words[2].Substring(2, 2), NmeaCultureInfo), // Month
                    int.Parse(words[2].Substring(0, 2), NmeaCultureInfo), // Day
                    int.Parse(words[3].Substring(0, 2), NmeaCultureInfo), // Hour
                    int.Parse(words[3].Substring(2, 2), NmeaCultureInfo), // Minute
                    int.Parse(words[3].Substring(4, 2), NmeaCultureInfo), // Second
                    DateTimeKind.Utc);
            }

            #region Position

            // Can we parse the latitude and longitude?
            if (wordCount >= 8 && words[5].Length != 0 && words[6].Length != 0 && words[7].Length != 0 && words[8].Length != 0)
            {
                #region Parse the latitude

                string latitudeWord = words[5];
                int latitudeHours = int.Parse(latitudeWord.Substring(0, 2), NmeaCultureInfo);
                double latitudeDecimalMinutes = double.Parse(latitudeWord.Substring(2), NmeaCultureInfo);
                LatitudeHemisphere latitudeHemisphere =
                    words[6].Equals("N", StringComparison.Ordinal) ? LatitudeHemisphere.North : LatitudeHemisphere.South;

                #endregion Parse the latitude

                #region Parse the longitude

                string longitudeWord = words[7];
                int longitudeHours = int.Parse(longitudeWord.Substring(0, 3), NmeaCultureInfo);
                double longitudeDecimalMinutes = double.Parse(longitudeWord.Substring(3), NmeaCultureInfo);
                LongitudeHemisphere longitudeHemisphere =
                    words[8].Equals("E", StringComparison.Ordinal) ? LongitudeHemisphere.East : LongitudeHemisphere.West;

                #endregion Parse the longitude

                #region Build a Position from the latitude and longitude

                _position = new Position(
                                new Latitude(latitudeHours, latitudeDecimalMinutes, latitudeHemisphere),
                                new Longitude(longitudeHours, longitudeDecimalMinutes, longitudeHemisphere));

                #endregion Build a Position from the latitude and longitude
            }
            else
            {
                _position = Position.Invalid;
            }

            #endregion Position

            #region Fix Mode

            if (wordCount >= 9 && words[9].Length != 0)
            {
                _fixMode = words[9] == "A" ? FixMode.Automatic : FixMode.Manual;
            }
            else
            {
                _fixMode = FixMode.Unknown;
            }

            #endregion Fix Mode

            #region Fix Quality

            // Do we have enough data for fix quality?
            if (wordCount >= 10 && words[10].Length != 0)
            {
                switch (int.Parse(words[10], NmeaCultureInfo))
                {
                    case 0:
                        _fixQuality = FixQuality.NoFix;
                        break;
                    case 1:
                        _fixQuality = FixQuality.GpsFix;
                        break;
                    case 2:
                        _fixQuality = FixQuality.DifferentialGpsFix;
                        break;
                    case 3:
                        _fixQuality = FixQuality.PulsePerSecond;
                        break;
                    case 4:
                        _fixQuality = FixQuality.FixedRealTimeKinematic;
                        break;
                    case 5:
                        _fixQuality = FixQuality.FloatRealTimeKinematic;
                        break;
                    case 6:
                        _fixQuality = FixQuality.Estimated;
                        break;
                    case 7:
                        _fixQuality = FixQuality.ManualInput;
                        break;
                    case 8:
                        _fixQuality = FixQuality.Simulated;
                        break;
                    default:
                        _fixQuality = FixQuality.Unknown;
                        break;
                }
            }
            else
            {
                // This fix quality is invalid
                _fixQuality = FixQuality.Unknown;
            }

            #endregion Fix Quality

            #region Bearing

            // Do we have enough data for fix quality?
            if (wordCount >= 13 && words[12].Length != 0)
            {
                _bearing = new Azimuth(words[12], NmeaCultureInfo);
            }
            else
            {
                _bearing = Azimuth.Invalid;
            }

            #endregion Bearing

            #region Speed

            // Do we have enough data for fix quality?
            if (wordCount >= 12 && words[11].Length != 0)
            {
                _speed = Speed.FromKilometersPerHour(double.Parse(words[11], NmeaCultureInfo));
            }
            else
            {
                _speed = Speed.Invalid;
            }

            #endregion Speed

            #region Position Dilution of Precision

            // Do we have enough data for fix quality?
            if (wordCount >= 13 && words[13].Length != 0)
            {
                _positionDop = new DilutionOfPrecision(float.Parse(words[13], NmeaCultureInfo));
            }
            else
            {
                _positionDop = DilutionOfPrecision.Invalid;
            }

            #endregion Position Dilution of Precision
        }
        /// <summary>
        /// Method to calculate all the data required for the graphs.
        /// </summary>
        private void OnAddReceiverClick(object sender, EventArgs e)
        {
            #region CreateAndConfigureReceiver
            // Let's create the GPSReceiver. The receiver stores many properties and has a defined location. This location
            // is the point of reference for visibility calculations.
            receiver = new GpsReceiver();

            // add receiver to the tree
            TreeNode newNode = new TreeNode(Localization.Receiver);
            rootNode.Nodes.Add(newNode);

            // Easy reference to Earth Central body used to initialize the ElevationAngleAccessConstraint and
            // to calculate the Az/El/Range Data.
            EarthCentralBody earth = CentralBodiesFacet.GetFromContext().Earth;

            // set the receiver properties based on user selections
            // The receiver has a receiver FrontEnd that contains the visibility and tracking constraints
            // Be sure to convert your angles to Radians!
            double minimumAngle = Trig.DegreesToRadians(Double.Parse(MaskAngle.Text));
            receiver.ReceiverConstraints.Clear();
            receiver.ReceiverConstraints.Add(new ElevationAngleConstraint(earth, minimumAngle));
            receiver.NumberOfChannels = (int)NumberOfChannels.Value;
            receiver.NoiseModel       = new ConstantGpsReceiverNoiseModel(0.8);

            // The receiver's methods of reducing the number of visible satellites to the limit imposed by the number of channels
            if (BestNSolType.Checked)
            {
                receiver.ReceiverSolutionType = GpsReceiverSolutionType.BestN;
            }
            else
            {
                receiver.ReceiverSolutionType = GpsReceiverSolutionType.AllInView;
            }

            // create a new location for the receiver by using the Cartographic type from AGI.Foundation.Coordinates
            // again, remember to convert from degrees to Radians! (except the height of course)
            Cartographic position = new Cartographic(Trig.DegreesToRadians(double.Parse(Longitude.Text)),
                                                     Trig.DegreesToRadians(double.Parse(Latitude.Text)),
                                                     double.Parse(ReceiverHeight.Text));

            // Now create an antenna for the GPS receiver. We specify the location of the antenna by assigning a
            // PointCartographic instance to the LocationPoint property. We specify that the antenna should be oriented
            // according to the typically-used East-North-Up axes by assigning an instance of AxesEastNorthUp to
            // the OrientationAxes property. While the orientation of the antenna won't affect which satellites are visible
            // or tracked in this case, it will affect the DOP values. For example, the EDOP value can be found in
            // DilutionOfPrecision.X, but only if we've configured the antenna to use East-North-Up axes.
            PointCartographic antennaLocationPoint = new PointCartographic(earth, position);
            Platform          antenna = new Platform
            {
                LocationPoint   = antennaLocationPoint,
                OrientationAxes = new AxesEastNorthUp(earth, antennaLocationPoint)
            };
            receiver.Antenna = antenna;

            #endregion

            // update the tree to reflect the correct receiver info
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.FixedMaskAngle + "= {0:0.00} " + Localization.degrees, MaskAngle.Text)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.NumberOfChannels + "= {0}", NumberOfChannels.Value)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.SolutionType + "= {0}", receiver.ReceiverSolutionType == GpsReceiverSolutionType.AllInView ? Localization.AllInView : Localization.BestN)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.Latitude + "= {0:0.000000} " + Localization.degrees, Latitude.Text)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.Longitude + "= {0:0.000000} " + Localization.degrees, Longitude.Text)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.Height + "= {0:0.000} " + Localization.meters, ReceiverHeight.Text)));

            rootNode.Expand();
            newNode.Expand();

            #region CalculateDataForGraphs

            // Now, we'll open the almanac
            SemAlmanac almanac;
            using (Stream stream = openAlmanacDialog.OpenFile())
                using (StreamReader reader = new StreamReader(stream))
                {
                    // Read the SEM almanac from an almanac stream reader.
                    almanac = SemAlmanac.ReadFrom(reader, 1);
                }

            // Now create a PlatformCollection to hold GpsSatellite object instances. The SemAlmanac method CreateSatellitesFromRecords returns
            // just such a collection. We'll use this set of satellites as the set from which we'll try and track. There is a
            // GpsSatellite object for each satellite specified in the almanac.
            PlatformCollection gpsSatellites = almanac.CreateSatelliteCollection();

            // We provide the receiver with the complete set of gpsSatellites to consider for visibility calculations.
            // This is usually all SVs defined in the almanac - however you may want to remove SVs that aren't healthy. This can
            // be done by creating the gpsSatellites collection above using another version of the CreateSatellitesFromRecords method that
            // takes a SatelliteOutageFileReader.
            receiver.NavigationSatellites = gpsSatellites;

            // Optimization opportunity: Add the following code in a thread. This will help for long duration analyses.

            // Now that we have the receiver and location setup, we need to evaluate all the pertinent data.
            // using a SatelliteTrackingEvaluator, we can track satellites and using a DOP Evaluator,
            // we can calculate DOP at a specified time.
            // The receiver's GetSatelliteTrackingEvaluator method will provide a SatelliteTrackingEvaluator for you.
            // Similarly, the GetDilutionOfPrecisionEvaluator provides the DOP evaluator.
            // We create all evaluators in the same EvaluatorGroup for the best performance.

            EvaluatorGroup    group = new EvaluatorGroup();
            Evaluator <int[]> satTrackingEvaluator       = receiver.GetSatelliteTrackingIndexEvaluator(group);
            Evaluator <DilutionOfPrecision> dopEvaluator = receiver.GetDilutionOfPrecisionEvaluator(group);

            // We also need to create an evaluator to compute Azimuth/Elevation for each of the SVs
            MotionEvaluator <AzimuthElevationRange>[] aerEvaluators = new MotionEvaluator <AzimuthElevationRange> [gpsSatellites.Count];
            for (int i = 0; i < gpsSatellites.Count; ++i)
            {
                Platform satellite            = receiver.NavigationSatellites[i];
                VectorTrueDisplacement vector = new VectorTrueDisplacement(antenna.LocationPoint, satellite.LocationPoint);
                aerEvaluators[i] = earth.GetAzimuthElevationRangeEvaluator(vector, group);
            }

            // First we'll initialize the data structures used to plot the data
            for (int i = 0; i < DOPData.Length; i++)
            {
                // PointPairList is defined in the ZedGraph reference
                DOPData[i] = new PointPairList();
            }

            // We need to know which time standard to use here. If the user has specified that GPS time is to be used
            // we need to create the JulianDates with the GlobalPositioningSystemTime standard.
            if (GPSTimeRadio.Checked)
            {
                startjd = new JulianDate(StartTime.Value, TimeStandard.GlobalPositioningSystemTime);
                stopjd  = new JulianDate(StopTime.Value, TimeStandard.GlobalPositioningSystemTime);
            }
            else
            {
                // otherwise, the default time standard is UTC
                startjd = new JulianDate(StartTime.Value);
                stopjd  = new JulianDate(StopTime.Value);
            }

            // Now we''ll create the variables we'll need for iterating through time.
            // The propagator requires a Duration type be used to specify the timestep.
            Duration dur      = stopjd - startjd;
            double   timestep = Double.Parse(TimeStep.Text);

            // Initialize the progressbar with appropriate values
            progressBar1.Maximum = (int)dur.TotalSeconds;
            progressBar1.Step    = (int)timestep;

            // now we'll iterate through time by adding seconds to the start time JulianDate
            // creating a new JulianDate 'evaluateTime' each time step.
            for (double t = 0; t <= dur.TotalSeconds; t += timestep)
            {
                JulianDate evaluateTime = startjd.AddSeconds(t);

                // The string 'trackedSVs' is the start of a string we'll continue to build through this time
                // iteration. It will contain the info we'll need to put in the DOP graph tooltips for the different
                // DOP series (VDOP, HDOP, etc.)
                String trackedSVs = Localization.Tracked + ": ";

                // The evaluator method GetTrackedSatellites will take the current time and the initial list of satellites and
                // determine which satellites can be tracked based on the receiver constraints setup earlier. This method
                // returns a PlatformCollection object as well (though we'll cast each member of the Collection to a GPSSatellite type)
                int[] trackedSatellites = satTrackingEvaluator.Evaluate(evaluateTime);

                foreach (int satelliteIndex in trackedSatellites)
                {
                    Platform satellite = receiver.NavigationSatellites[satelliteIndex];

                    // Now we have access to a Platform object representing a GPS satellite and calculate the azimuth and elevation
                    // of each.  Note that we're just calculating the azimuth and elevation, but could just as easily get the
                    // range as well.
                    AzimuthElevationRange aer = aerEvaluators[satelliteIndex].Evaluate(evaluateTime);

                    // Get the GpsSatelliteExtension attached to the platform. The extension extends a
                    // platform with GPS-specific information. In this case, we need the
                    // satellites PRN.
                    GpsSatelliteExtension extension = satellite.Extensions.GetByType <GpsSatelliteExtension>();

                    // Create two separate PointPairLists to hold the data stored by Time and Azimuth
                    PointPairList thisTimePointList, thisAzPointList;

                    // Before we can arbitrarily create new PointPair Lists, we have to see if the Data Storage structures already contain a list
                    // for this PRN.
                    // The variables AzElData_TimeBased and AzElData_AzimuthBased are dictionaries that hold the PointPairLists using the PRN
                    // as a key. We use this structure to store a large amount of data for every satellite in a single, easy to access, variable.
                    // if the satellite we're currently looking at already has a list defined in the dictionary, we'll use that one, otherwise
                    // we'll create a new list
                    if (AzElData_TimeBased.ContainsKey(extension.PseudoRandomNumber))
                    {
                        thisTimePointList = AzElData_TimeBased[extension.PseudoRandomNumber];
                        AzElData_TimeBased.Remove(extension.PseudoRandomNumber);
                    }
                    else
                    {
                        thisTimePointList = new PointPairList();
                    }

                    if (AzElData_AzimuthBased.ContainsKey(extension.PseudoRandomNumber))
                    {
                        thisAzPointList = AzElData_AzimuthBased[extension.PseudoRandomNumber];
                        AzElData_AzimuthBased.Remove(extension.PseudoRandomNumber);
                    }
                    else
                    {
                        thisAzPointList = new PointPairList();
                    }

                    // Now to get the actual Azimuth and elevation data

                    // Converting your Radians to degrees here makes the data appear in a more readable format. We also constrain the azimuth
                    // to be within the interval [0, 2*pi]
                    double azimuth   = Trig.RadiansToDegrees(Trig.ZeroToTwoPi(aer.Azimuth));
                    double elevation = Trig.RadiansToDegrees(aer.Elevation);
                    #endregion

                    // now create the point for the Azimuth based data
                    PointPair thisAzPoint = new PointPair(azimuth, elevation);
                    // and add the tooltip (ZedGraph uses the Tag property on a PointPair for the tooltip on that datapoint )
                    thisAzPoint.Tag = String.Format("PRN {0}, {1}, " + Localization.Az + ": {2:0.000}, " + Localization.El + ": {3:0.000}", extension.PseudoRandomNumber, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), azimuth, elevation);
                    // and finally add this point to the list
                    thisAzPointList.Add(thisAzPoint);

                    // now we'll do the same for the time-based data, instead of adding the Az and El, we'll add the time and El.
                    // Create a new XDate object to store the time for this point
                    double txd = (double)new XDate(evaluateTime.ToDateTime());
                    // add the time and elevation data to this point
                    PointPair thisTimePoint = new PointPair(txd, Trig.RadiansToDegrees(aer.Elevation));
                    // Create the tooltip tag
                    thisTimePoint.Tag = String.Format("PRN {0}, {1}, " + Localization.Az + ": {2:0.000}, " + Localization.El + ": {3:0.000}", extension.PseudoRandomNumber, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), azimuth, elevation);
                    // finally add this point to the list
                    thisTimePointList.Add(thisTimePoint);

                    //Now that this data is all calculated, we'll add the point lists to the correct data structures for the GpsSatellite we're working with
                    AzElData_TimeBased.Add(extension.PseudoRandomNumber, thisTimePointList);
                    AzElData_AzimuthBased.Add(extension.PseudoRandomNumber, thisAzPointList);

                    // now update the 'trackedSVs' string to be used for the DOP data tooltip
                    // wee need to do this inside the GpsSatellite loop because we need to get the entire list of tracked SVs for this time step.
                    // we won't use this string until we're out of the loop however.
                    trackedSVs += extension.PseudoRandomNumber.ToString() + ", ";
                }

                // now we're out of the GpsSatellite loop, we'll do some string manipulation to get the tooltip for the DOP data.
                // (gets rid of the last inserted comma)
                string svs = trackedSVs.Substring(0, trackedSVs.LastIndexOf(' ') - 1);
                try
                {
                    // Now we use the evaluator to calculate the DilutionOfPrecision for us for this timestep
                    DilutionOfPrecision dop = dopEvaluator.Evaluate(evaluateTime);

                    // if the dop object throws an exception, there aren't enough tracked satellites to form a navigation solution (typically < 4 tracked)
                    // in that case we leave the data for this time unfilled. The graph will then have empty spots for this time.

                    // Here we create a new PointPair and a new XDate to add to the X-Axis
                    PointPair pp;
                    double    txd = (double)new XDate(evaluateTime.ToDateTime());
                    // add the East DOP value and the time to the PointPair and set the tooltip tag property for this series.
                    pp     = new PointPair(txd, dop.X);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.EDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.X);
                    // add the point to the 0th element of the DOPData structure
                    DOPData[0].Add(pp);
                    // repeat for North DOP
                    pp     = new PointPair(txd, dop.Y);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.NDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Y);
                    DOPData[1].Add(pp);
                    // repeat for the Vertical DOP
                    pp     = new PointPair(txd, dop.Z);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.VDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Z);
                    DOPData[2].Add(pp);
                    // repeat for the Horizontal DOP
                    pp     = new PointPair(txd, dop.XY);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.HDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.XY);
                    DOPData[3].Add(pp);
                    // repeat for the Position DOP
                    pp     = new PointPair(txd, dop.Position);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.PDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Position);
                    DOPData[4].Add(pp);
                    // repeat for the Time DOP
                    pp     = new PointPair(txd, dop.Time);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.TDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Time);
                    DOPData[5].Add(pp);
                    // repeat for the Geometric DOP
                    pp     = new PointPair(txd, dop.Geometric);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.GDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Geometric);
                    DOPData[6].Add(pp);

                    // Notice here that the different DOP values (East, North, etc) were denoted by the dop.X, dop.Y etc. This is because the
                    // DOP values could be in any coordinate system. In our case, we're in the ENU coordinate system an X represents East, Y
                    // represents North, Z represents Vertical, XY represents horizontal. You can change the reference frame the DOP is reported in
                    // but you will then have to understand that the dop.X value corresponds to your X-defined axis and so on.
                }
                catch
                {
                    // Do Nothing here - we just won't add the data to the data list
                }
                // update the progress bar - we're done with this time step!
                progressBar1.PerformStep();
            }
            // finally update the graphs
            UpdateDopGraph();
            updateAzElGraph();

            // reset the progress bar
            progressBar1.Value = 0;

            // and set the appropriate button states
            SetControlStates(true);
        }
     /// <summary>
     /// Initializes a new instance of the <see cref="KalmanSystemState"/> struct.
     /// </summary>
     /// <param name="gpsPosition">The GPS position.</param>
     /// <param name="deviceError">The device error.</param>
     /// <param name="horizontalDOP">The horizontal DOP.</param>
     /// <param name="verticalDOP">The vertical DOP.</param>
     /// <param name="ellipsoid">The ellipsoid.</param>
     internal KalmanSystemState(
 Position3D gpsPosition, Distance deviceError,
 DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP,
 Ellipsoid ellipsoid)
         : this(
             gpsPosition, deviceError, verticalDOP, horizontalDOP, ellipsoid,
             CartesianPoint.Empty, CartesianPoint.Invalid, gpsPosition.ToCartesianPoint(),
             null, null, null,
             null, null, null)
     { }
Exemple #39
0
 /// <summary>
 /// Creates a new instance with the specified DOP measurement.
 /// </summary>
 /// <param name="dilutionOfPrecision">The dilution of precision.</param>
 public DilutionOfPrecisionEventArgs(DilutionOfPrecision dilutionOfPrecision)
 {
     DilutionOfPrecision = dilutionOfPrecision;
 }
 /// <summary>
 /// Updates the state.
 /// </summary>
 /// <param name="currentDOP">The current DOP.</param>
 /// <param name="z">The z.</param>
 public void UpdateState(DilutionOfPrecision currentDOP, Position3D z)
 {
     UpdateState(Distance.FromMeters(_deviceError), currentDOP, currentDOP, Azimuth.Empty, Speed.AtRest, z);
 }
        protected override void OnSentenceChanged()
        {
            base.OnSentenceChanged();

            // Cache the sentence words
            string[] words     = base.Words;
            int      wordCount = words.Length;

            /*
             *  Garmin produces several embedded GPS systems. They are easy to setup because Garmin provides a nice utility for uploading configuration data to the GPS. You first load the utility to a PC. Connect the PC to the GPS through one of the serial ports. The utility will check each baud rate until it communicates with the GPS.
             *
             *  The common configuration parameters are output sentences from the GPS unit, the communication baud rate with a host, and the required pulse per second.
             *
             *  Each sentence is preceded with a ‘$’ symbol and ends with a line-feed character. At one sentence per second, the following is out put in four seconds:
             *
             *  $PGRMF,223,424798,041203,215945,13,0000.0000,N,00000.0000,W,A,2,0,62,2,1*3B
             *  $PGRMF,223,424799,041203,215946,13,00000.0000,N,00000.0000,W,A,2,0,62,2,1*39
             *  $PGRMF,223,424800,041203,215947,13,00000.0000,N,00000.0000,W,A,2,0,62,2,1*34
             *  $PGRMF,223,424801,041203,215948,13,00000.0000,N,00000.0000,W,A,2,0,62,2,1*35
             *
             *  The sentence is proprietary to the Garmin GPS Global Positioning System and is translated below.
             *
             *  $PGRMF
             *  <1>GPS Week Number(0-1023)
             *  <2>GPS Seconds (0 - 604799)
             *  <3>UTC Date of position fix, ddmmyy format
             *  <4>UTC time of position fix, hhmmss format
             *  <5>GPS leap second count
             *  <6>Latitude, ddmm.mmmm format (leading zeros transmitted)
             *  <7>Latitude hemisphere N or S
             *  <8>Longitude, ddmm.mmmm format (leading zeros transmitted)
             *  <9>Longitude hemisphere N or S
             *  <10>Mode M = Manual, A automatic
             *  <11>Fix type 0 = No Fix, 1 = 2D Fix, 2 = 3D fix
             *  <12>Speed over ground, 0 to 359 degrees true
             *  <13>Course over ground, 0 to 9 (rounded to nearest intvalue)
             *  <14>Time dilution of precision, 0 to 9 (rnded nearest int val)
             *  <15>Time dilution of precision, 0 to 9 (rnded nearest int val)
             * hh <CR><LF>
             */

            // TODO: Convert GPS week number/seconds to UTC date/time

            // Do we have enough words to parse the fix status?
            if (wordCount >= 4 && words[2].Length != 0 && words[3].Length != 0)
            {
                // Build a UTC date/time object.
                _UtcDateTime = new DateTime(
                    int.Parse(words[2].Substring(4, 2), NmeaCultureInfo) + 2000, // Year
                    int.Parse(words[2].Substring(2, 2), NmeaCultureInfo),        // Month
                    int.Parse(words[2].Substring(0, 2), NmeaCultureInfo),        // Day
                    int.Parse(words[3].Substring(0, 2), NmeaCultureInfo),        // Hour
                    int.Parse(words[3].Substring(2, 2), NmeaCultureInfo),        // Minute
                    int.Parse(words[3].Substring(4, 2), NmeaCultureInfo),        // Second
                    DateTimeKind.Utc);
            }

            #region Position

            // Can we parse the latitude and longitude?
            if (wordCount >= 8 && words[5].Length != 0 && words[6].Length != 0 && words[7].Length != 0 && words[8].Length != 0)
            {
                #region Parse the latitude

                string             latitudeWord           = words[5];
                int                latitudeHours          = int.Parse(latitudeWord.Substring(0, 2), NmeaCultureInfo);
                double             latitudeDecimalMinutes = double.Parse(latitudeWord.Substring(2), NmeaCultureInfo);
                LatitudeHemisphere latitudeHemisphere     =
                    words[6].Equals("N", StringComparison.Ordinal) ? LatitudeHemisphere.North : LatitudeHemisphere.South;

                #endregion

                #region Parse the longitude

                string longitudeWord                    = words[7];
                int    longitudeHours                   = int.Parse(longitudeWord.Substring(0, 3), NmeaCultureInfo);
                double longitudeDecimalMinutes          = double.Parse(longitudeWord.Substring(3), NmeaCultureInfo);
                LongitudeHemisphere longitudeHemisphere =
                    words[8].Equals("E", StringComparison.Ordinal) ? LongitudeHemisphere.East : LongitudeHemisphere.West;

                #endregion

                #region Build a Position from the latitude and longitude

                _Position = new Position(
                    new Latitude(latitudeHours, latitudeDecimalMinutes, latitudeHemisphere),
                    new Longitude(longitudeHours, longitudeDecimalMinutes, longitudeHemisphere));

                #endregion
            }
            else
            {
                _Position = Position.Invalid;
            }

            #endregion

            #region Fix Mode

            if (wordCount >= 9 && words[9].Length != 0)
            {
                if (words[9] == "A")
                {
                    _FixMode = FixMode.Automatic;
                }
                else
                {
                    _FixMode = FixMode.Manual;
                }
            }
            else
            {
                _FixMode = FixMode.Unknown;
            }

            #endregion

            #region Fix Quality

            // Do we have enough data for fix quality?
            if (wordCount >= 10 && words[10].Length != 0)
            {
                switch (int.Parse(words[10], NmeaCultureInfo))
                {
                case 0:
                    _FixQuality = FixQuality.NoFix;
                    break;

                case 1:
                    _FixQuality = FixQuality.GpsFix;
                    break;

                case 2:
                    _FixQuality = FixQuality.DifferentialGpsFix;
                    break;

                case 3:
                    _FixQuality = FixQuality.PulsePerSecond;
                    break;

                case 4:
                    _FixQuality = FixQuality.FixedRealTimeKinematic;
                    break;

                case 5:
                    _FixQuality = FixQuality.FloatRealTimeKinematic;
                    break;

                case 6:
                    _FixQuality = FixQuality.Estimated;
                    break;

                case 7:
                    _FixQuality = FixQuality.ManualInput;
                    break;

                case 8:
                    _FixQuality = FixQuality.Simulated;
                    break;

                default:
                    _FixQuality = FixQuality.Unknown;
                    break;
                }
            }
            else
            {
                // This fix quality is invalid
                _FixQuality = FixQuality.Unknown;
            }

            #endregion

            #region Bearing

            // Do we have enough data for fix quality?
            if (wordCount >= 13 && words[12].Length != 0)
            {
                _Bearing = new Azimuth(words[12], NmeaCultureInfo);
            }
            else
            {
                _Bearing = Azimuth.Invalid;
            }

            #endregion

            #region Speed

            // Do we have enough data for fix quality?
            if (wordCount >= 12 && words[11].Length != 0)
            {
                _Speed = Speed.FromKilometersPerHour(double.Parse(words[11], NmeaCultureInfo));
            }
            else
            {
                _Speed = Speed.Invalid;
            }

            #endregion

            #region Position Dilution of Precision

            // Do we have enough data for fix quality?
            if (wordCount >= 13 && words[13].Length != 0)
            {
                _PositionDOP = new DilutionOfPrecision(float.Parse(words[13], NmeaCultureInfo));
            }
            else
            {
                _PositionDOP = DilutionOfPrecision.Invalid;
            }


            #endregion
        }
     /// <summary>
     /// Kalman Filter with parameters
     /// </summary>
     /// <param name="initialObservation">The initial observation.</param>
     /// <param name="deviceError">The device error.</param>
     /// <param name="horizontalDOP">The horizontal DOP.</param>
     /// <param name="verticalDOP">The vertical DOP.</param>
     /// <param name="ellipsoid">The ellipsoid.</param>
     public KalmanFilter(
 Position3D initialObservation,
 Distance deviceError,
 DilutionOfPrecision horizontalDOP,
 DilutionOfPrecision verticalDOP,
 Ellipsoid ellipsoid)
     {
         _currentState = new KalmanSystemState(
             initialObservation,
             deviceError,
             horizontalDOP,
             verticalDOP,
             ellipsoid);
     }
        /// <summary>
        /// Copies the settings of the NMEA Emulator.
        /// </summary>
        /// <returns> A new NMEA Emulator with the same settings. </returns>
        //public override Emulator Clone()
        //{
        //    // Make a new emulator
        //    NmeaEmulator emulator = (NmeaEmulator)Clone(new NmeaEmulator());

        //    emulator._HorizontalDOP = _HorizontalDOP;
        //    emulator._VerticalDOP = _VerticalDOP;
        //    emulator._MeanDOP = _MeanDOP;
        //    emulator._FixMode = _FixMode;
        //    emulator._FixStatus = _FixStatus;
        //    emulator._FixMethod = _FixMethod;
        //    emulator._FixQuality = _FixQuality;
        //    emulator._MagneticVariation = _MagneticVariation;

        //    emulator._minHDOP = _minHDOP;
        //    emulator._maxHDOP = _maxHDOP;
        //    emulator._minVDOP = _minVDOP;
        //    emulator._maxVDOP = _maxVDOP;

        //    return emulator;
        //}

        public override void Randomize()
        {
            // Randomize the base emulation for speed/bearing
            base.Randomize();

            _HorizontalDOP = new DilutionOfPrecision((float)(Seed.NextDouble() * (_maxHDOP - _minHDOP) + _minHDOP));
            _VerticalDOP   = new DilutionOfPrecision((float)(Seed.NextDouble() * (_maxVDOP - _minVDOP) + _minVDOP));

            // Mean is hypotenuse of the (X,Y,Z,n) axes.
            _MeanDOP = new DilutionOfPrecision((float)Math.Sqrt(Math.Pow(_HorizontalDOP.Value, 2) + Math.Pow(_VerticalDOP.Value, 2)));

            lock (Satellites)
            {
                if (Satellites.Count == 0)
                {
                    int sats = Seed.Next(4, 12);

                    //Satellites.Add(new Satellite(32, new Azimuth(225), new Elevation(45), new SignalToNoiseRatio(25)));

                    Satellites.Add(new Satellite(32, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    if (sats > 1)
                    {
                        Satellites.Add(new Satellite(24, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 2)
                    {
                        Satellites.Add(new Satellite(25, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 3)
                    {
                        Satellites.Add(new Satellite(26, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 4)
                    {
                        Satellites.Add(new Satellite(27, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 5)
                    {
                        Satellites.Add(new Satellite(16, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 6)
                    {
                        Satellites.Add(new Satellite(14, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 7)
                    {
                        Satellites.Add(new Satellite(6, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 8)
                    {
                        Satellites.Add(new Satellite(7, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 9)
                    {
                        Satellites.Add(new Satellite(4, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 10)
                    {
                        Satellites.Add(new Satellite(19, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                    if (sats > 11)
                    {
                        Satellites.Add(new Satellite(8, new Azimuth(Seed.Next(360)), new Elevation(Seed.Next(90)), new SignalToNoiseRatio(Seed.Next(50))));
                    }
                }
            }

            SetRandom(true);
        }
 /// <summary>
 /// Initializes the Kalman Filter using an initial observation (position)
 /// </summary>
 /// <param name="gpsPosition">The position at which tfilter is to begin opperating.</param>
 /// <param name="deviceError">Distance of the error</param>
 /// <param name="horizontalDOP">The horizontal dilution of precision</param>
 /// <param name="verticalDOP">The vertical dilution of precision</param>
 /// <param name="ellipsoid">The ellipsoid</param>
 public void Initialize(Position gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Ellipsoid ellipsoid)
 {
     _currentState = new KalmanSystemState(new Position3D(gpsPosition), deviceError, horizontalDOP, verticalDOP, ellipsoid);
 }
Exemple #45
0
 /// <summary>
 /// Does the initialize.
 /// </summary>
 private void DoInitialize()
 {
     _altitude = Distance.Invalid;
     _altitudeAboveEllipsoid = _altitude;
     _bearing = Azimuth.Invalid;
     _heading = Azimuth.Invalid;
     _fixStatus = FixStatus.Unknown;
     _horizontalDop = DilutionOfPrecision.Maximum;
     _magneticVariation = Longitude.Invalid;
     _position = Position.Invalid;
     _speed = Speed.Invalid;
     _meanDop = DilutionOfPrecision.Invalid;
     _verticalDop = DilutionOfPrecision.Invalid;
     if (_satellites != null)
         _satellites.Clear();
 }
 /// <summary>
 /// Initializes the Kalman Filter using an initial observation (position)
 /// </summary>
 /// <param name="gpsPosition">The position at which tfilter is to begin opperating.</param>
 /// <param name="deviceError">A distance measure of device error</param>
 /// <param name="meanDOP">The mean dilution of precision</param>
 /// <param name="ellipsoid">The ellipsoid</param>
 public void Initialize(Position3D gpsPosition, Distance deviceError, DilutionOfPrecision meanDOP, Ellipsoid ellipsoid)
 {
     Initialize(gpsPosition, deviceError, meanDOP, meanDOP, ellipsoid);
 }
Exemple #47
0
        /// <summary>
        /// Updates the precision as it relates to latitude, longitude and altitude.
        /// </summary>
        /// <param name="value">The value.</param>
        protected virtual void SetMeanDilutionOfPrecision(DilutionOfPrecision value)
        {
            // If the new value is the same or it's invalid, ignore it
            if (_meanDop.Equals(value) || value.IsInvalid)
                return;

            // Yes.  Update the value
            _meanDop = value;

            // And notify of the change
            if (MeanDilutionOfPrecisionChanged != null)
                MeanDilutionOfPrecisionChanged(this, new DilutionOfPrecisionEventArgs(_meanDop));
        }
 /// <summary>
 /// Returns the position
 /// </summary>
 /// <param name="gpsPosition">The gps Position</param>
 /// <param name="currentDOP">The current dilution of precision</param>
 /// <returns>A Position sturcture</returns>
 public Position Filter(Position gpsPosition, DilutionOfPrecision currentDOP)
 {
     return Filter(gpsPosition, _currentState.DeviceError, currentDOP, currentDOP, Azimuth.Empty, Speed.AtRest);
 }
        protected virtual Distance EmulateError(DilutionOfPrecision dop)
        {
            // Calculate the error variance
            //return Distance.FromMeters((Seed.NextDouble() * dop.Value) + DilutionOfPrecision.CurrentAverageDevicePrecision.ToMeters().Value); really? isn't that what the estimated precision is for and shouldn't it be +/- the estimated precision range divided by 2 as below
            return Distance.FromMeters(dop.EstimatedPrecision.ToMeters().Value * (Seed.NextDouble() - 0.5));

        }
 /// <summary>
 /// Adds a new observation and applies the filter.
 /// </summary>
 /// <param name="gpsPosition"> The new observation to add to the filter. </param>
 /// <param name="deviceError"> Does not currently affect position averaging. </param>
 /// <param name="horizontalDOP"> Does not currently affect position averaging. </param>
 /// <param name="verticalDOP"> Does not currently affect position averaging. </param>
 /// <param name="bearing"> Does not currently affect position averaging. </param>
 /// <param name="speed"> Does not currently affect position averaging. </param>
 /// <remarks>
 /// This method updates the FilteredLocation property without consideration for SampleCount.
 /// </remarks>
 public override Position Filter(Position gpsPosition, Distance deviceError, DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP, Azimuth bearing, Speed speed)
 {
     Position3D pos3d = Filter(new Position3D(gpsPosition), deviceError, horizontalDOP, verticalDOP, bearing, speed);
     return new Position(pos3d.Latitude, pos3d.Longitude);
 }
Exemple #51
0
        internal KalmanSystemState(
            Position3D gpsPosition, Distance deviceError,
            DilutionOfPrecision horizontalDOP, DilutionOfPrecision verticalDOP,
            Ellipsoid ellipsoid,
            CartesianPoint u, CartesianPoint x, CartesianPoint z,
            SquareMatrix3D A, SquareMatrix3D B, SquareMatrix3D H,
            SquareMatrix3D P, SquareMatrix3D Q, SquareMatrix3D R)
        {
            this._deviceError = deviceError.IsEmpty ? DilutionOfPrecision.CurrentAverageDevicePrecision.Value : deviceError.Value;
            this._horizontalDOP = horizontalDOP.IsEmpty ? DilutionOfPrecision.Good.Value : horizontalDOP.Value;
            this._verticalDOP = verticalDOP.IsEmpty ? DilutionOfPrecision.Good.Value : verticalDOP.Value;
            this._ellipsoid = ellipsoid == null ? Ellipsoid.Default : ellipsoid;

            double hCovariance = this._deviceError * this._horizontalDOP;
            double vCovariance = this._deviceError * this._verticalDOP;

            this.u = u.IsInvalid ? CartesianPoint.Empty : u;
            this.x = x;
            this.z = z.IsInvalid ? CartesianPoint.Empty : z;

            this.A = A == null ? new SquareMatrix3D() : A;
            this.B = B == null ? new SquareMatrix3D() : B;
            this.H = H == null ? new SquareMatrix3D() : H;
            this.P = P == null ? new SquareMatrix3D() : P;
            this.Q = Q == null ? SquareMatrix3D.Default(0) : Q;
            this.R = R == null ? new SquareMatrix3D(
                hCovariance, 0, 0,
                0, hCovariance, 0,
                0, 0, vCovariance) : R;

            this._interval = 0;

            this._errorState = Math.Sqrt(Math.Pow(hCovariance, 2) + Math.Pow(vCovariance, 2));

            this._delay = TimeSpan.MaxValue;
            this._lastObservation = DateTime.MinValue;

            if (!gpsPosition.IsEmpty)
                Initialize(gpsPosition);
        }
        protected Emulator(string name)
        {
            _Name = name;

            // Create new buffers for reading and writing
            _ReadBuffer = new List<byte>(_DefaultReadBufferSize);
            _WriteBuffer = new List<byte>(_DefaultWriteBufferSize);

            // Initialize simulated values
            _ReadDataAvailableWaitHandle = new ManualResetEvent(false);
            _WriteDataAvailableWaitHandle = new ManualResetEvent(false);
            _EmulationIntervalWaitHandle = new ManualResetEvent(false);

            // Default timeouts for reading and writing
            _ReadTimeout = _DefaultReadTimeout;
            _WriteTimeout = _DefaultWriteTimeout;
            
            // Simulated values
            _seed = new Random();
            _UtcDateTime = DateTime.UtcNow;
            _CurrentPosition = GeoFramework.Position.Empty;            
            _Altitude = Distance.FromFeet(1000);
            _Route = new List<Position>();
            _Satellites = new List<Satellite>();
            _FixQuality = FixQuality.GpsFix;
            _FixMode = FixMode.Automatic;
            _FixMethod = FixMethod.Fix3D;
            _FixStatus = FixStatus.Fix;
            _HorizontalDop = DilutionOfPrecision.Good;
            _VerticalDop = DilutionOfPrecision.Good;
            _MeanDop = DilutionOfPrecision.Good;

            _Speed = Speed.FromStatuteMilesPerHour(20);
            _speedLow = Speed.FromKilometersPerSecond(10).Value;
            _speedHigh = Speed.FromKilometersPerSecond(25).Value;

            _Bearing = Azimuth.Southwest;
            _bearingStart = _seed.NextDouble() * 360;
            _bearingArc = 10;

        }
Exemple #53
0
 protected virtual Distance EmulateError(DilutionOfPrecision dop)
 {
     // Calculate the error variance
     //return Distance.FromMeters((Seed.NextDouble() * dop.Value) + DilutionOfPrecision.CurrentAverageDevicePrecision.ToMeters().Value); really? isn't that what the estimated precision is for and shouldn't it be +/- the estimated precision range divided by 2 as below
     return(Distance.FromMeters(dop.EstimatedPrecision.ToMeters().Value *(Seed.NextDouble() - 0.5)));
 }