Оглавление:

Среднее значение для ваших проектов микроконтроллеров: 6 шагов
Среднее значение для ваших проектов микроконтроллеров: 6 шагов

Видео: Среднее значение для ваших проектов микроконтроллеров: 6 шагов

Видео: Среднее значение для ваших проектов микроконтроллеров: 6 шагов
Видео: Лекция №1 "Микроконтроллеры" (Донов Г.И.) 2024, Ноябрь
Anonim
Среднее значение для ваших проектов микроконтроллеров
Среднее значение для ваших проектов микроконтроллеров

В этом руководстве я объясню, что такое скользящее среднее и почему вы должны о нем заботиться, а также покажу вам, как его следует реализовать для максимальной вычислительной эффективности (не беспокойтесь о сложности, это очень просто для понимания, и я предоставьте простую в использовании библиотеку для ваших проектов Arduino:)

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

Шаг 1. Пример использования: сглаживание измерений АЦП

Пример использования: сглаживание измерений АЦП
Пример использования: сглаживание измерений АЦП

У Arduino есть приличный 10-битный АЦП с очень небольшим шумом. При измерении значения на датчике, таком как потенциометр, фоторезистор или другие компоненты с высоким уровнем шума, трудно поверить в правильность измерения.

Одно из решений - выполнять несколько измерений каждый раз, когда вы хотите считать показания датчика и усреднить их. В некоторых случаях это жизнеспособное решение, но не всегда. Если вы хотите считывать АЦП 1000 раз в секунду, вам нужно будет 10 000, если вы сделаете в среднем 10 измерений. Огромная трата вычислительного времени.

Предлагаемое мной решение - проводить измерения 1000 раз в секунду, каждый раз обновлять текущее среднее значение и использовать его в качестве текущего значения. Этот метод вызывает некоторую задержку, но снижает вычислительную сложность вашего приложения, давая вам гораздо больше времени для дополнительной обработки.

На картинке выше я использовал среднее значение последних 32 измерений. Вы увидите, что этот метод не является 100% отказоустойчивым, но он значительно повышает точность (это не хуже, чем усреднение 32 выборок каждый раз). Если вы хотите вычислять в среднем 32 измерения каждый раз, это заняло бы более 0,25 мс на Arduino UNO только для измерений!

Шаг 2. Пример использования: измерение составляющей постоянного тока сигнала микрофона

Пример использования: измерение постоянной составляющей сигнала микрофона
Пример использования: измерение постоянной составляющей сигнала микрофона
Пример использования: измерение постоянной составляющей сигнала микрофона
Пример использования: измерение постоянной составляющей сигнала микрофона
Пример использования: измерение постоянной составляющей сигнала микрофона
Пример использования: измерение постоянной составляющей сигнала микрофона

Arduino может измерять напряжения от 0 до Vcc (обычно 5 В). Аудиосигнал является полностью переменным током, и если вы хотите измерить его на микроконтроллере, вы должны смещать его примерно на 1/2 В постоянного тока. В проекте Arduino UNO это будет означать примерно 2,5 В (постоянного тока) + аудиосигнал (переменного тока). При использовании 10-битного АЦП и источника питания 5 В смещение 2,5 В должно равняться измеренному значению 512. Итак, чтобы получить значение переменного тока сигнала, необходимо вычесть 512 из измерения АЦП, и все, верно?

В идеальном мире это было бы правдой. К сожалению, реальная жизнь более сложна, и наши искажения сигнала имеют тенденцию дрейфовать. Очень распространен шум 50 Гц (60 Гц, если вы живете в США) от электрической сети. Обычно это не так уж и сложно, но хорошо знать, что он существует. Более проблематичным является линейный дрейф от нагрева компонентов. Вы тщательно устанавливаете коррекцию смещения постоянного тока при запуске, и она медленно уходит по мере выполнения вашего приложения.

Я проиллюстрирую эту проблему с помощью (музыкального) детектора ударов. Вы настраиваете удаление смещения, и удары четкие (рисунок 2). Через некоторое время смещения постоянного тока смещаются и биения становятся едва заметными для микроконтроллера (рисунок 3). Алгоритм обнаружения биений будет подробно рассмотрен в будущем, поскольку он выходит за рамки данной статьи.

К счастью, есть способ постоянно рассчитывать смещение постоянного тока аудио. Неудивительно, что бегущее среднее, тема этого руководства, дает решение.

Мы знаем, что среднее значение любого сигнала переменного тока равно 0. Используя это знание, мы можем вычесть, что среднее значение сигнала переменного + постоянного тока является его смещением постоянного тока. Чтобы удалить его, мы можем взять текущее среднее последних нескольких значений и вычесть его из текущего показания АЦП. Обратите внимание, что вам нужно использовать достаточно длительное среднее значение. Для звука достаточно одной десятой секунды (количество отсчетов зависит от вашей частоты дискретизации), но знайте, что более длинные средние значения работают лучше. На первом рисунке вы можете увидеть пример расчета реального смещения постоянного тока со скользящим средним с 64 элементами при частоте дискретизации 1 кГц (меньше, чем я рекомендовал, но он все еще работает).

Шаг 3: Расчет

Расчет
Расчет

Вы можете представить себе бегущее среднее значение как средний вес людей в приемной врача. Доктор заканчивает осмотр одного пациента, и одновременно в приемную входит новый.

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

Вы можете подумать: «Это звучит не слишком эффективно… Должен быть способ сделать это лучше». И ты был бы прав.

Для оптимизации этого процесса медсестра может вести учет общего веса текущей группы пациентов. Как только врач вызывает нового пациента, медсестра спрашивает его о его весе, вычитает его из общей суммы группы и отпускает. Затем медсестра спрашивала пациента, который только что вошел в комнату ожидания, о его весе и добавляла его к общей сумме. Средний вес пациентов после каждой смены будет суммой весов, деленной на количество пациентов (да, так же, как и раньше, но теперь медсестра спрашивала об их весе только двух человек, а не всех). Я понимаю, что этот абзац мог немного сбить с толку, поэтому для большей ясности просмотрите иллюстрацию выше (или задавайте вопросы в комментариях).

Но даже если вы не сочли последний абзац запутанным, у вас могут возникнуть вопросы, например, что должно быть в аккумуляторе в начале, как мне поместить то, что я только что прочитал, в реальный код C? Это будет рассмотрено на следующем шаге, где вы также получите мой исходный код.

Шаг 4: Код

Код
Код

Чтобы вычислить скользящее среднее, вам сначала понадобится способ сохранить последние N значений. у вас может быть массив с N элементами и перемещать все содержимое на одно место каждый раз, когда вы добавляете элемент (пожалуйста, не делайте этого), или вы можете перезаписать один старый элемент и настроить указатель на следующий элемент, который будет выброшен (пожалуйста, сделайте это:)

Аккумулятор должен начать инициализироваться до 0, то же самое касается всех элементов в линии задержки. В противном случае ваше текущее среднее всегда будет неправильным. Вы увидите, что delayLine_init заботится об инициализации линии задержки, вы должны сами позаботиться об аккумуляторе.

добавить элемент в линию задержки так же просто, как уменьшить индекс самого нового элемента на 1, убедившись, что он не указывает на сторону массива линии задержки. после уменьшения индекса, когда он равен 0, он будет возвращаться к 255 (потому что это 8-битное целое число без знака). Оператор по модулю (%) с размером массива линий задержки гарантирует, что индекс будет указывать на действительный элемент.

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

Легко, правда?

Не стесняйтесь экспериментировать с использованием прилагаемого кода, чтобы лучше понять, как все это работает. В настоящее время arduino считывает аналоговое значение на аналоговом выводе A0 и печатает «[значение АЦП], [текущее среднее]» на последовательном порту со скоростью 115200 бод. Если вы откроете последовательный плоттер Arduino с правильной скоростью передачи, вы увидите две строки: значение АЦП (синий) и сглаженное значение (красный).

Шаг 5: Дополнительно

Дополнительно
Дополнительно

Есть несколько вещей, которые вам не обязательно знать, чтобы использовать среднее значение в своем проекте, но это не повредит.

delay: Я начну с иллюстрации этого шага. Вы заметите, что среднее значение большего количества элементов приводит к большей задержке. Если время отклика на изменение значения имеет решающее значение, вы можете использовать более короткое скользящее среднее или увеличить частоту дискретизации (измеряйте чаще).

Двигаемся дальше.

Инициализация: Когда я говорил об инициализации элементов аккумулятора и задержки, я сказал, что вы должны инициализировать их все равными 0. В качестве альтернативы вы можете инициализировать линию задержки как угодно, но аккумулятор должен запускаться как сумма новейших N элементов в линии задержки (где N - количество элементов в вашем среднем значении). Если аккумулятор запускается как любое другое значение, вычисленное среднее будет неверным - либо слишком низким, либо слишком высоким, всегда на одну и ту же величину (при одинаковых начальных условиях). Я предлагаю вам попытаться понять, почему это так, используя имитацию ручки и бумаги.

размер аккумулятора: вы также должны отметить, что аккумулятор должен быть достаточно большим, чтобы хранить сумму всех элементов в линии задержки, если они все положительные или отрицательные макс. Фактически это означает, что аккумулятор должен быть на один тип данных больше, чем элементы линии задержки и подписан, если элементы линии задержки подписаны.

Уловка: длинные линии задержки занимают много памяти. Это может быстро стать проблемой. Если вы сильно ограничены в памяти и не заботитесь о точности, вы можете приблизиться к текущему среднему, полностью исключив задержку и сделав это вместо этого: вычтите 1 / N * аккумулятора из аккумулятора и добавьте новое значение (в примере 8 длительных средних значений: аккумулятор = аккумулятор * 7/8 + новое значение). Этот метод дает неправильный результат, но это достойный метод расчета среднего значения при нехватке памяти.

лингвистика: «скользящее среднее / среднее» обычно используется, когда речь идет об усреднении в реальном времени, в то время как «скользящее среднее / среднее» обычно означает, что алгоритм работает на статическом наборе данных, таком как электронная таблица Excel.

Шаг 6: Заключение

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

Рекомендуемые: