示例#1
0
        /// <summary>
        /// calculate vmc and vmg values if possible with current state
        /// </summary>
        /// <param name="state">current race state</param>
        public void Calculate(State state)
        {
            if (state.Location != null && state.TargetMark != null && state.TargetMark.Location != null && state.Course is CourseByMarks)
            {
                double meters = CoordinatePoint.HaversineDistance(state.Location, state.TargetMark.Location);
                if (meters < _distanceCutoff)//if the reported distance is more than this threshold, it's probably garbage data
                {
                    state.StateValues[StateValue.DistanceToTargetMarkInYards] = meters * MetersToYards;
                }

                var calculation = new MarkCalculation();
                calculation.Location = state.Location;
                calculation.Time     = state.BestTime;

                _previousCalculations.Add(calculation);
                while (_previousCalculations.Count > _previousCalculationCount)
                {
                    _previousCalculations.RemoveAt(0);
                }

                if (_previousCalculations.Count > 1)
                {
                    var previous = _previousCalculations[_previousCalculations.Count - 2];
                    var duration = calculation.Time - previous.Time;

                    //calculate vmc
                    var previousDistanceMeters = CoordinatePoint.HaversineDistance(previous.Location,
                                                                                   state.TargetMark.Location);
                    var distanceDelta      = previousDistanceMeters - meters;
                    var vmcMetersPerSecond = distanceDelta / duration.TotalSeconds;
                    var vmcKnots           = MetersPerSecondToKnots * vmcMetersPerSecond;
                    calculation.VelocityMadeGoodOnCourse = vmcKnots;
                    state.StateValues[StateValue.VelocityMadeGoodOnCourse] = vmcKnots;                    //_previousCalculations.Average(x => x.VelocityMadeGoodOnCourse);

                    state.StateValues[StateValue.VelocityMadeGoodOnCoursePercent] = vmcKnots / state.StateValues[StateValue.SpeedInKnots] * 100;

                    //TODO: calculate vmg
                    if (state.PreviousMark != null && state.StateValues.ContainsKey(StateValue.SpeedInKnots))
                    {
                        calculation.VelocityMadeGood = VelocityMadeGood(state.TargetMark, state.PreviousMark,
                                                                        calculation.Location, previous.Location, state.StateValues[StateValue.SpeedInKnots]);

                        state.StateValues[StateValue.VelocityMadeGoodPercent] = calculation.VelocityMadeGood.Value / state.StateValues[StateValue.SpeedInKnots] * 100;

                        var relativeAngle = RelativeAngleToCourse(state.TargetMark, state.PreviousMark, calculation.Location, previous.Location);
                        state.StateValues[StateValue.CourseOverGroundRelativeToCourse] = AngleUtilities.RadiansToDegrees(relativeAngle);
                    }
                }
            }
            else if (state.Course is CourseByAngle && state.StateValues.ContainsKey(StateValue.CourseOverGroundDirection) && state.StateValues.ContainsKey(StateValue.SpeedInKnots))
            {
                state.StateValues[StateValue.VelocityMadeGood]        = VelocityMadeGood((state.Course as CourseByAngle).CourseAngle, state.StateValues[StateValue.CourseOverGroundDirection], state.StateValues[StateValue.SpeedInKnots]);
                state.StateValues[StateValue.VelocityMadeGoodPercent] = state.StateValues[StateValue.VelocityMadeGood] / state.StateValues[StateValue.SpeedInKnots] * 100;

                var relativeAngle = AngleUtilities.AngleDifference(AngleUtilities.DegreestoRadians((state.Course as CourseByAngle).CourseAngle), AngleUtilities.DegreestoRadians(state.StateValues[StateValue.CourseOverGroundDirection]));
                state.StateValues[StateValue.CourseOverGroundRelativeToCourse] = AngleUtilities.RadiansToDegrees(relativeAngle);
            }
        }
示例#2
0
        public static void VmgTest()
        {
            double courseAngle      = 270;
            double courseOverGround = 270 - 45;
            double speed            = 10;

            double courseAngleRadians      = AngleUtilities.DegreestoRadians(courseAngle);
            double courseOverGroundRadians = AngleUtilities.DegreestoRadians(courseOverGround);

            double difference = AngleUtilities.AngleDifference(courseAngleRadians, courseOverGroundRadians);


            var cos = Math.Cos(difference);

            var vmg = cos * speed;

            vmg = MarkCalculator.VelocityMadeGood(courseAngle, courseOverGround, speed);


            Console.WriteLine(string.Format("VMG:{0:0.00}\tVMG%:{1:0.00}", vmg, (vmg / speed * 100)));
        }
示例#3
0
        /// <inheritdoc />
        public void Calculate(State state)
        {
            if (state.StateValues.ContainsKey(StateValue.CourseOverGroundDirection))
            {
                var cogRads = AngleUtilities.DegreestoRadians(state.StateValues[StateValue.CourseOverGroundDirection]);

                //make sure whe're not in an "exclusion" aka a few seconds before/after a known tack
                if (!_lastTackAt.HasValue || (_lastTackAt.Value + _dataExclusionTime < state.BestTime))
                {
                    if (!_currentTackStartCourseOverGroundRadians.HasValue)
                    {
                        _currentTackStartCourseOverGroundRadians = cogRads;
                    }
                    _history.Add(new CourseHistory()
                    {
                        Time = state.BestTime, CourseOverGroundRadians = cogRads
                    });

                    //make sure we have enough data to do the calculation accurately
                    if (_history.Count > 1)
                    {
                        if (_history.Max(x => x.Time) - _history.Min(x => x.Time) > _tackThresholdTime)
                        {
                            CheckForTack(state);
                        }
                    }
                }

                //calculate the delta on the current tack
                if (state.StateValues.ContainsKey(StateValue.CourseOverGroundDirection) && _currentTackStartCourseOverGroundRadians.HasValue)
                {
                    var delta = AngleUtilities.AngleDifference(cogRads, _currentTackStartCourseOverGroundRadians.Value);
                    state.StateValues[StateValue.CurrentTackCourseOverGroundDelta] = AngleUtilities.RadiansToDegrees(delta);
                }
            }

            PurgeOldHistory();
        }
示例#4
0
 /// <summary>
 /// calculate vmg from raw values
 /// </summary>
 /// <param name="courseAngle"></param>
 /// <param name="courseOverGround"></param>
 /// <param name="speed"></param>
 /// <returns></returns>
 public static double VelocityMadeGood(double courseAngle, double courseOverGround, double speed)
 {
     return(Math.Cos(Math.Abs(AngleUtilities.AngleDifference(AngleUtilities.DegreestoRadians(courseAngle), AngleUtilities.DegreestoRadians(courseOverGround)))) * speed);
 }