View Categories

Оверсэмплинг

Оверсэмплинг (oversampling) - методика повышения разрядности целочисленного цифрового сигнала, часто используется для повышения разрешения АЦП. Простыми словами - позволяет математически очень просто повысить точность измерений и добавить к ним несколько двоичных разрядов, т.е. условно из 10-бит сигнала (значения 0.. 1023) получить 12 бит (0.. 4095) и выше. Бывает реализовано аппаратно в некоторых АЦП.

Математика #

В основе метода лежит самое обыкновенное среднее арифметическое, а также предположение, что АЦП шумит гармонически и "взвешенно". Для оверсэмплинга нужно усреднить несколько значений с АЦП, прочитанных подряд без пауз, т.е. мы рассчитываем получить шум самого АЦП.

Например, если с АЦП получаются значения 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 uint16_t OVS_SAMPLES(uint8_t gain) {
    return 1ul << (gain << 1);
}

// число, на которое нужно сдвинуть сумму
constexpr uint32_t OVS_SHIFT(uint8_t gain) {
    return gain;
}

// максимальное значение при начальном разрешении
constexpr uint16_t OVS_MAX(uint8_t base, uint8_t gain) {
    return (1ul << (gain + base)) - (1 << gain);
}

Пример - расчёт напряжения на АЦП при помощи оверсэмплинга с 10 бит (по умолч. analogRead Arduino) до 12 бит:

uint32_t sum = 0;

for (uint16_t i = 0; i < OVS_SAMPLES(2); i++) {
    sum += analogRead(0);
}

sum >>= OVS_SHIFT(2);

// теперь sum - 12 битное значение с АЦП

Библиотека #

У меня есть готовая библиотека OVS с этими функциями и классом-обёрткой.

Полезные страницы #

Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Прокрутить вверх