Избегайте шума 1-LSB в показаниях АЦП
У меня есть потенциометр, подключенный к входу АЦП Arduino Leonardo. Разрешение АЦП 10-битное (0..1024), а мне нужно всего 7-битное (0..127).
Я использую простой фильтр, чтобы уменьшить шум, а затем map
, чтобы удалить неиспользуемые биты:
#define ADC_CH 18
#define ADC_FILTER 0.90
uint16_t value;
uint16_t adc = analogRead(ADC_CH);
value = (uint16_t) ((float) ADC_FILTER * adc + (1. - ADC_FILTER) * value);
Я показываю value
на ЖК-дисплее. Это очень стабильно, но может случиться так, что если показания АЦП находятся рядом с двумя значениями, нет ничего, что могло бы предотвратить изменение конечного значения, даже если шум составляет всего несколько младших разрядов.
Есть ли простой способ реализовать гистерезис для каждого значения с низким разрешением?
Таким образом, изменение между N и N+1 происходит при другом показании АЦП, чем между N и N-1, что улучшает подавление шума без увеличения задержки фильтра (это только увеличило бы интервал изменения).
@Mark, 👍1
1 ответ
Лучший ответ:
Когда вы уменьшаете разрешение с 10 бит до 7 бит, все возможные выход соответствует интервалу входов. Если добавить немного гистерезиса, то эти интервалы должны перекрываться. Ниже представлено представление входные интервалы, соответствующие выходам 0, 1,… 6, для ширина гистерезиса 4:
input: 0 5 10 15 20 25 30 35 40 45 50 55 60
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴
├─────0────┤
├───────1──────┤
├───────2──────┤
├───────3──────┤
├───────4──────┤
├───────5──────┤
├───────6──────┤
Чтобы реализовать это в коде, вы должны помнить последний вывод и измените его только в том случае, если вход находится за пределами интервала, назначенного этому выход. Вот пример реализации:
const int hysteresis = 4; // настраиваем по вкусу
/* Удалить 3 бита разрешения, добавив немного гистерезиса. */
int resample(int adc)
{
static int value; // последний вывод
if (adc < (value<<3) - hysteresis) {
value = (adc + hysteresis) >> 3;
} else if (adc >= ((value+1)<<3) + hysteresis) {
value = (adc - hysteresis) >> 3;
}
return value;
}
Обратите внимание, что локальная переменная static
сохраняет свое значение между последовательными
вызовы функции.
- Ускорение двигателя постоянного тока с помощью ШИМ
- Потенциометр отображает только аналоговое значение напряжения 1023 в proteus
- Проблема с потенциометром ESP32: несоответствие разрешения потенциометра с неограниченным разрешением и считывание значений с помощью Wire.h
- Соединение АЦП при создании миди-контроллера (множество потенциометров)
- Гистерезис и диапазон масштабирования
- Постоянный выход тактовой частоты Arduino
- Как эмулировать аналоговый потенциометр с помощью ШИМ
- Расширение аналоговых входов для Arduino
Я не должен этого делать, но в любом случае: отличный ответ! Хорошая графика, хорошо объяснено. :), @Nick Gammon
Ваш код работает отлично и точно соответствует примеру в моем вопросе. В любом случае, есть ли более общий подход? Например, что, если я хочу «сопоставить» вход АЦП с [min, max](всегда < 1024)?, @Mark
@Mark: Затем вы замените сдвиги (которые в основном представляют собой оптимизированные умножения и деления) на произвольные карты
map()
. Затем вы можете провести некоторые тесты, чтобы увидеть, как ошибки округления, вносимые картой, влияют на гистерезис., @Edgar Bonet