Оверсэмплинг (oversampling) - методика повышения эффективного разрешения цифрового сигнала, часто используется с АЦП. Простыми словами - при подходящих условиях позволяет добавить несколько двоичных разрядов, т.е. условно из 10-битного сигнала получить 12 бит и выше. Оверсэмплинг уменьшает случайный шум и повышает разрешение, но не исправляет смещение, нелинейность и другие систематические ошибки АЦП. Бывает реализован аппаратно в некоторых АЦП.
Математика #
В основе метода лежит самое обыкновенное среднее арифметическое. Чтобы получить дополнительные биты информации, входной сигнал должен содержать случайный шум или специально добавленный дизер хотя бы около одного младшего разряда АЦП - если все чтения строго одинаковые или шум коррелирован, простое суммирование не создаст новых данных.
Например, если с АЦП получаются значения 300, 300, 300, 301 и 300, то можно предположить, что среднее значение будет 300.2. Переход к дробным числам не всегда удобен, особенно во встраиваемой электронике - здесь и пригодится оверсэмплинг. Идея в том, что мы точно так же складываем несколько измерений, но не будем делить их на количество - вместо этого просто примем, что разрешение увеличилось и данные теперь находятся в другом диапазоне. В программировании всё привязано к степеням двойки, поэтому и переходить к новому диапазону удобнее в битах, чтобы оптимизировать вычисления и удобнее ориентироваться в значениях.
Для этого нужно сложить определённое количество измерений (сэмплов, samples) и разделить на коэффициент в зависимости от желаемого увеличения разрешения. В общем случае всё это описывается вот такими формулами:
| Значение | Формула | +1 | +2 | +3 | +4 |
|---|---|---|---|---|---|
| Кол-во сэмплов | 4^GAIN |
4 |
16 |
64 |
256 |
| Делитель суммы | 2^GAIN |
2 |
4 |
8 |
16 |
| Новый максимум | 2^(CUR + GAIN) - 2^GAIN |
Где GAIN - увеличение разрешения (на количество бит), а CUR - текущее разрешение сигнала в битах.
Новый максимум будет слегка отличаться от ожидаемого - например мы повысили разрешение с 10 до 12 бит и ожидаем, что в новом диапазоне будет максимальное значение 2^12 - 1 = 4095, например для перевода значения в Вольты. Но оверсэмплинг слегка уменьшает максимум - он будет равен 4092 по формуле выше. Это почти незначительно и можно пренебречь в расчётах, но если нужно максимально точное значение - лучше брать расчётный максимум.
Код #
Для максимальной производительности приведённые выше формулы можно оптимизировать до следующего вида, а деление - до сдвига:
// количество измерений, которое нужно сделать
constexpr uint32_t OVS_SAMPLES(uint8_t gain) {
return 1ul << (gain << 1);
}
// число, на которое нужно сдвинуть сумму
constexpr uint8_t OVS_SHIFT(uint8_t gain) {
return gain;
}
// максимальное значение при начальном разрешении
constexpr uint32_t OVS_MAX(uint8_t base, uint8_t gain) {
return (1ul << (gain + base)) - (1ul << gain);
}
Пример - расчёт напряжения на АЦП при помощи оверсэмплинга с 10 бит (по умолч. analogRead Arduino) до 12 бит:
uint32_t sum = 0;
for (uint32_t i = 0; i < OVS_SAMPLES(2); i++) {
sum += analogRead(0);
}
sum >>= OVS_SHIFT(2);
// теперь sum - 12 битное значение с АЦП
В этих функциях используются 32-битные сдвиги, поэтому сумма, количество измерений и выражение base + gain должны помещаться в 32 бита. Для обычного перехода с 10 до 12 бит запас большой, а экстремальные значения gain сюда передавать нельзя.
Измерения не обязаны идти вообще без пауз. Важно сохранить нужную частоту дискретизации и захватить независимые состояния шума, не пропустив полезные изменения сигнала
Библиотека #
У меня есть готовая библиотека OVS с этими функциями и классом-обёрткой.
Полезные страницы #
- Набор GyverKIT – наш большой стартовый набор Arduino, продаётся в России
- Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress
- Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту (alex@alexgyver.ru)
- Поддержать автора за работу над уроками