В настоящее время я занимаюсь разработкой графической ЖК-системы для отображения температуры, потоков, напряжений, мощности и энергии в системе с тепловым насосом. Использование графического ЖК-дисплея означает, что половина моей SRAM и ~ 75% моей флэш-памяти были израсходованы экранным буфером и строками.
В настоящее время я отображаю минимальные / максимальные / средние значения для энергии. В полночь, когда дневной показатель сбрасывается, система проверяет, превышает ли потребление за день предыдущий минимум или максимум, и сохраняет значение. Среднее значение рассчитывается путем деления совокупного потребления энергии на количество дней.
Я хотел бы отобразить среднесуточное значение за последнюю неделю и месяц (4 недели для простоты), то есть скользящее среднее. В настоящее время это включает в себя ведение массива значений за последние 28 дней и вычисление среднего значения по всему массиву за месяц и за последние 7 дней за неделю.
Первоначально я делал это с использованием массива чисел с плавающей запятой (поскольку энергия находится в форме «12,12 кВт · ч»), но при этом использовалось 28 * 4 байта = 112 байтов (5,4% от SRAM). Я не против иметь только одну десятичную точку разрешения, поэтому я перешел на использование uint16_t и умножил цифру на 100. Это означает, что 12.12 представляется как 1212, и я делю на 100 для целей отображения.
Размер массива теперь уменьшен до 56 байт (намного лучше!).
Нет никакого тривиального способа уменьшить число до uint8_t, которое я вижу. Я мог бы допустить потерю десятичного разряда («12,1 кВт / ч» вместо «12,12 кВт / ч»), но потребление часто выше, чем 25,5 кВт / ч (255 - самое высокое значение, представленное 8-разрядным целым числом без знака). Потребление никогда не было ниже 10,0 кВт или выше 35,0 кВт, поэтому, возможно, я мог бы вычесть 10 из сохраненных цифр, но я знаю, что однажды мы превысим эти пределы.
Затем я протестировал код для упаковки 9-битных значений в массив. Это дает диапазон от 0 до 51,2 кВт / ч и использует в общей сложности 32 байта. Однако доступ к массиву, подобному этому, довольно медленный, особенно когда вам приходится перебирать все значения, чтобы вычислить среднее значение.
Итак, мой вопрос - есть ли более эффективный способ расчета скользящего среднего с тремя окнами - срок службы, 28 дней и 7 дней? Эффективность означает меньшую с точки зрения использования SRAM, но без потери огромного кода. Могу ли я избежать хранения всех значений?
источник
Ответы:
Если ваши данные имеют низкое стандартное отклонение, то одним из методов будет суммирование значений по окну, а затем продолжайте вычитать среднее из суммы, добавляя новое значение.
Это будет хорошо работать, если нет выбросов , что приведет к совокупной ошибке, стремящейся к нулю с течением времени.
источник
Вы можете использовать другой метод, вы сохраняете текущее среднее и затем делаете
это не истинное скользящее среднее и имеет другую семантику, но, тем не менее, оно может соответствовать вашим потребностям
для более эффективного метода вычисления для вашего решения 9 битов на значение вы можете сохранить 8 старших битов значений в массиве и выделить младшие биты:
чтобы установить значение, вам нужно разделить его
в результате 2 сдвигов И и ИЛИ и не
для вычисления среднего вы можете использовать различные битовые трюки, чтобы ускорить его:
вы можете использовать эффективный параллельный битовый счет для
bitcount()
источник
Как насчет сохранения только разницы от предыдущего значения? В электронике существует аналогичная концепция, называемая преобразователем Delta Sigma, которая используется для преобразователей DA / AD. Он основан на том факте, что предыдущее измерение достаточно близко к текущему.
источник
Почему вы не можете просто добавить значения вместе, как только вы их получите. Итак, я имею в виду, что вы получаете значение для первого дня, делите его на 1 и сохраняете где-то 1 и 1. Затем вы умножаете 1 на значение и добавляете его к следующему значению и делите их на 2.
Выполнение этого метода создаст скользящее среднее с двумя или тремя переменными, как я могу себе представить. Я бы написал немного кода, но я новичок в stackexchange, поэтому, пожалуйста, потерпите меня.
источник
Вы можете получить достаточно близко, храня 11 значений, а не 28 значений, возможно, что-то вроде:
Другими словами, вместо того, чтобы хранить каждую деталь каждого дня в течение последних 27 дней, (а) сохраняйте 7 или около того значений подробной ежедневной информации за последние 7 дней или около того, а также (б) сохраняйте 4 или около того «суммированных» значения общей или средней информации для каждой из последних 4 или около того недель.
источник