Какие классы алгоритмов уменьшают погрешность в непрерывном потоке ввода? - PullRequest
1 голос
/ 20 апреля 2011

Машина проводит измерения и непрерывно выдает мне дискретные числа, например:

1 2 5 7 8 10 11 12 13 14 18

Допустим, эти измерения могут быть отключены на 2 точки, и измерение генерируется каждые 5 секунд. Я хочу игнорировать измерения, которые потенциально могут быть одинаковыми

Как непрерывные 2 и 3 могут быть одинаковыми, так как погрешность равна 2, так как я могу разделить данные так, чтобы я получал только отдельные измерения, но я также хотел бы справиться с ситуацией, в которой измерения непрерывно увеличиваются следующим образом:

1 2 3 4 5 6 7 8 9 10

В этом случае, если мы будем игнорировать последовательные числа с разницей менее 2, то мы можем потерять фактические измерения.

Есть ли класс алгоритмов для этого? Как бы вы решили это?

Ответы [ 3 ]

2 голосов
/ 20 апреля 2011

Просто отбросьте любое число, которое находится «в диапазоне» предыдущего (сохраненного). Это должно просто работать.

Для вашего возрастающего примера:

1 сохраняется, 2 отбрасывается, потому что находится в диапазоне 1, 3 отбрасывается, потому что находится в диапазоне 1, затем 4 сохраняется, 5 и 6 сбрасывается в диапазоне 4, затем 7 сохраняется и т. Д. Таким образом, вы по-прежнему сохраняете тенденцию к увеличению, если она достаточно велика (чего вы хотите, верно?

В исходном примере вы получите 1,5,8,11,14,18.

1 голос
/ 20 апреля 2011

В некоторых направлениях работы стандартным способом решения проблем такого рода является использование фильтра Калмана.

Цитировать Википедия :

Его [фильтр Калмана] предназначен для использования измерений наблюдается со временем, содержащий шум (случайные вариации) и другие неточности, и производят ценности, которые как правило, ближе к истинным значениям измерений и их соответствующие расчетные значения.

Сам фильтр очень прост в применении, но требует калибровки.

0 голосов
/ 21 апреля 2011

У меня было бы две очереди:

  • Временная очередь
  • Окончательная очередь / список

Ваше первое значение попадет во временную очередь и вокончательный список.Когда поступают новые значения, проверьте, находится ли новое значение в зоне нечувствительности последнего значения в списке.Если это так, добавьте его во временную очередь.Если нет, то добавьте его в окончательный список.Если ваша временная очередь начинает увеличиваться в размерах, прежде чем вы получите новое значение за пределами зоны нечувствительности, то, как только вы окажетесь за пределами зоны нечувствительности, выполните проверку, чтобы увидеть, монотонно увеличиваются или уменьшаются значения все время.Если они всегда увеличиваются или уменьшаются, добавьте содержимое очереди в окончательный список, в противном случае просто добавьте одно новое значение в окончательный список.Это общая суть.

Вот код, который я быстро создал, который реализует класс для выполнения того, что я описал выше:

public class MeasurementsFilter
    {
        private Queue<int> tempQueue = new Queue<int>();
        private List<int> finalList = new List<int>();

        private int deadband;

        public MeasurementsFilter(int deadband)
        {
            this.deadband = deadband;
        }

        public void Reset()
        {
            finalList.Clear();
            tempQueue.Clear();
        }

        public int[] FinalValues()
        {
            return finalList.ToArray();
        }

        public void AddNewValue(int value)
        {
            // if we are just starting then the first value always goes in the list and queue
            if (tempQueue.Count == 0)
            {
                tempQueue.Enqueue(value);
                finalList.Add(value);
            }
            else
            {
                // if the new value is within the deadband of the last value added to the final list
                // then enqueue the value and wait
                if ((tempQueue.Peek() - deadband <= value) && (value <= tempQueue.Peek() + deadband))
                {
                    tempQueue.Enqueue(value);
                }
                // else the new value is outside of the deadband of the last value added to the final list
                else
                {

                    tempQueue.Enqueue(value);

                    if (QueueIsAlwaysIncreasingOrAlwaysDecreasing())
                    {
                        //dequeue first item (we already added it to the list before, but we need it for comparison purposes)
                        int currentItem = tempQueue.Dequeue();

                        while (tempQueue.Count > 0)
                        {
                            // if we are not seeing two in a row of the same (i.e. they are not duplicates of each other)
                            // then add the newest value to the final list
                            if (currentItem != tempQueue.Peek())
                            {
                                currentItem = tempQueue.Dequeue();
                                finalList.Add(currentItem);
                            }
                            // otherwise if we are seeing two in a row (i.e. duplicates)
                            // then discard the value and loop to the next value
                            else
                            {
                                currentItem = tempQueue.Dequeue();
                            }

                        }

                        // add the last item from the final list back into the queue for future deadband comparisons
                        tempQueue.Enqueue(finalList[finalList.Count - 1]);

                    }
                    else
                    {
                        // clear the queue and add the new value to the list and as the starting point of the queue
                        // for future deadband comparisons
                        tempQueue.Clear();
                        tempQueue.Enqueue(value);
                        finalList.Add(value);
                    }


                }
            }
        }

        private bool QueueIsAlwaysIncreasingOrAlwaysDecreasing()
        {
            List<int> queueList = new List<int>(tempQueue);

            bool alwaysIncreasing = true;
            bool alwaysDecreasing = true;

            int tempIncreasing = int.MinValue;
            int tempDecreasing = int.MaxValue;

            int i = 0;

            while ((alwaysIncreasing || alwaysDecreasing) && (i < queueList.Count))
            {
                if (queueList[i] >= tempIncreasing)
                    tempIncreasing = queueList[i];
                else
                    alwaysIncreasing = false;

                if (queueList[i] <= tempDecreasing)
                    tempDecreasing = queueList[i];
                else
                    alwaysDecreasing = false;

                i++;

            }

            return (alwaysIncreasing || alwaysDecreasing);

        }
    }

Вот тестовый код, который вы можетедобавить в событие Winform Load или нажать кнопку:

int[] values = new int[] { 1, 2, 2, 1, 4, 8, 3, 2, 1, 0, 6 };

            MeasurementsFilter filter = new MeasurementsFilter(2);

            for (int i = 0; i < values.Length; i++)
            {
                filter.AddNewValue(values[i]);
            }


            int[] finalValues = filter.FinalValues();

            StringBuilder printValues = new StringBuilder();

            for (int i = 0; i < finalValues.Length; i++)
            {
                printValues.Append(finalValues[i]);
                printValues.Append(" ");
            }

            MessageBox.Show("The final values are: " + printValues);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...