| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Алгоритмы > Вычисление отсечки для скользящего окна по количес |
| Автор: TrnasitionMan 27.12.2016, 10:40 |
| Друзья, Направьте на путь истинный. Пытаюсь сообразить алгоритм для следующей задачи. Причем, алгоритм хочется получить простой, так как аппаратные ресурсы скромные, но ум постепенно заходит за разум. Итак, задача. Раз в секунду на входное устройство поступает сигнал, который может быть логическим нулем или единицей. Задача поднять флаг, если количество единиц за заданный промежуток времени превысит установленный лимит. Т.е. в наличие бесконечный дискретный поток данных, в которых надо отлавливать единички и смотреть сколько единичек поймалось за установленный период времени. Пример 1: Окно времени = 40 секунд Количество единиц = 8 штук Пример 2: Окно времени = 3600 секунд Количество единиц = 6 штук Решать в лоб, т.е. заводить массив размерностью в окно времени, а затем каждую итерацию его двигать, очень не хочется. На другом форуме предлагался вариант со счетчиком: Окно времени = 3600 секунд Количество единиц = 1200 Доля (окно на количество единиц) = 3 Изначальное состояние счетчика = 3600+3, при 0 на входе увеличиваем значение счетчика на 1, если значение счетчика меньше изначального состояния. При 1 уменьшаем значение счетчика на 3. Флаг поднимается когда счетчик <=0. В целом он работает, но получаются неточности (в сторону увеличения) при получении на входе последовательности из 010101010101. И чем больше значения количества единиц и окна времени, тем больше возникает ошибка. Пока попробовал различные варианты, включая кучу и два счетчика. Но как-то не выходит каменный цветок. Срубается на описанной выше последовательности. Что думаете? |
| Автор: Akina 27.12.2016, 11:09 |
| От хранения состояний за текущее окно никуда тебе не деться - или ты будешь определять состояние только с некоей долей вероятности. Так что можно только оптимизировать решение с хранением. Я бы делал так: 1) Создаём массив размером в окно времени, заполняем нулями. 2) Создаём указатель на текущее местоположение, равный началу массива. 3) Создаём счётчик, равный нулю. При поступлении очередного сигнала: Счётчик = Счётчик - Значение по текущему указателю + Поступивший сигнал Элемент по текущему указателю = Поступивший сигнал Текущий указатель = (Текущий указатель + 1) MOD Размер окна Если (Счётчик >= Порог) Флаг = 1 Иначе Флаг = 0 Профиты: 1) Не нужно двигать элементы массива. 2) Минимальное количество вычислений по получению нового значения счётчика. 3) Хранение актуального значения счётчика. |
| Автор: TrnasitionMan 27.12.2016, 11:54 |
| Нутром чую, что можно обойтись вообще без массива или его аналога. В текущей версии алгоритма используется два счетчика, срабатывание стабильное в рамках Window или Window+1... На куралесицу с 01010101 срабатывание нормально. |
| Автор: Lipetsk 27.12.2016, 12:28 |
| если единички редки, а промежутки велики, то можно запоминать только моменты времени, в которые были получены единички |
| Автор: TrnasitionMan 27.12.2016, 13:29 | ||
Последовательность поступления единичек никак не нормируется. Совершенно стохастический процесс. Насчет сохранения времени я думал, возможно это вариант, тем более, что время в системе считается. Пока хочу разобраться со счетчиками. |
| Автор: TrnasitionMan 27.12.2016, 13:58 | ||||
Да, понимаете предложенный алгоритм верно, за исключением того, что счетчик не увеличивается более окно+окно/доля и не опускается менее 0, это условия алгоритма. Но, я его погонял несколько раз и там есть проблема связанная с чередованием нулей и единиц. В этом случае флаг поднимается позже чем следует. Причем чем больше величины, тем больше получается разбег. Сейчас я протестировал алгоритм с четырьмя переменными-счетчиками, работает намного стабильнее, но в некоторых случаях срабатывает на Window+1. Что не есть сильно критично, но просто не красиво. Попробую его нарисовать, для наглядности.... Пока он в виде формул в экселе. |
| Автор: TrnasitionMan 27.12.2016, 14:19 | ||
Так, текущая версия с двумя счетчиками и их предыдущими состояниями:
Что думаете? |
| Автор: Akina 27.12.2016, 14:25 | ||
В таком случае предложенный расчёт надо подкорректировать - итоговое значение счётчика будет 2401, но это всё равно куда как больше нуля... косяк, короче, а не метода. Да вот думаю, не написать ли в отместку свой ответ на корейском... |
| Автор: TrnasitionMan 28.12.2016, 10:42 | ||
[QUOTE=Akina,27.12.2016, 14:25]
Если попробовать описать его словами, то получается нечто следующее: Переменные: Флаг Входящий поток Окно Дозволенное время работы Счетчик1 Предыдущее состояние Счетчик1 Счетчик2 Предыдущее состояние Счетчик2 Начальное состояние: Счетчик1=Предыдущее состояние Счетчик1=0 Счетчик2=Дозволенное время работы Предыдущее состояние Счетчик2=0 Флаг=ложь Условия изменения переменных: Флаг=истина когда Счетчик2=0 или когда Флаг был истина в предыдущей итерации. Условие увеличения Счетчик1: Увеличивается на 1, когда Входящий поток =0 и пока Предыдущее состояние Счетчик1 меньше Окно Условие увеличения Счетчик2: Увеличивается на 1, когда Входящий поток =0, Предыдущее состояние Счетчик1 равно разницы Окно и Дозволенное время работы, Предыдущее состояние Счетчик2 меньше Дозволенное время работы. Все по логическому И. Условие уменьшения Счетчик1: Уменьшается на 1, когда Входящий поток = 1 и Предыдущее состояние Счетчик 1>0 Условие уменьшения Счетчик2: Уменьшается на 1, когда Входящий поток = 1 и Предыдущее состояние Счетчик2 >0 Суть алгоритма на движении двух счетчиков. Вначале, когда алгоритм только запущен, движение идет разнонаправленное, после прохождения времени Окно, движение во время остуствия поступления единичек однонаправленное. Фишка в том, что Счетчик2 растет, только когда Счетчик1 достигает размера Окно. |