Линеаризация характеристики АЦП

Столкнулся с нелинейной характеристикой АЦП. Поиск в инете готовой функции линеаризации ничего не дал. Видимо каждый придумавает что-то свое и не хочет делиться )).
Ну ничего, будем ваять.
Первое что пришло на ум, сделать калибровочную таблицу по нескольким точкам и линейную аппроксимацию промежуточных точек.
Можно записать в таблицу показания лабораторного вольтметра и АЦП, а можно только вольтметра для значений АЦП с постоянным шагом (0,10,20,..), тогда, имея код АЦП, легко определить индекс в таблице, где хранится значение вольтметра. Индекс = целая часть(код АЦП)/Шаг.
Далее по двум точкам определяем уравнение прямой y=kx+b, подставляем в уравнение значение АЦП как х, на выходе получим напряжение.
Уравнение прямой в общем виде:

k = (y2-y1)/(x2-x1)
b = (x2y1-x1y2)/(x2-x1)
Ну что же, вроде бы все просто. Значения х соотвествуют коду АЦП, вычисляются как Индекс*Шаг, y — берется из таблицы.

Пробуем запрограммировать

/* таблица калибровки (показания вольтметра) */
float tk[11] = {0, 0.8, 1.7, 2.8, 3.4, 4.4, 5.3, 6.2, 7.2, 8.1, 9};
float t1[10] = {0.3, 0.5, 3.5, 5.6, 7.8, 3.3, 4.9, 6.6, 8.7, 0}; // таблица значений
float out[10]; // буфер выходных значений
#define step 1 /* шаг */

float Linear(float x)
{
   unsigned char i = x/step;
   float b = (i+1)*tk[i] - i*tk[i+1];
   float k = (tk[i+1] - tk[i]) / step;
   return k*x+b;
}

void main()
{
  unsigned char i;
    for (i=0;i<10;i++)
    {
       out[i] = Linear(t1[i]);
    }
   while(1){};
}

Все значения в таблице забиты для теста.
Вот что получилось в резутате:

На графике
ряд1(синий) — выходные значения(линеаризованные показания);
ряд2(малиновый)- калибровочная таблица;
ряд3(желтый) — входные значения до калибровки.

Комментарии (11)

RSS свернуть / развернуть
… у Atmel есть апликэйшн ноут AVR120 на эту тему, правда без кода, но формулы хорошо расписаны
0
в AVR 120 написано как ошибку усиления и смещения можно компенсировать, умножив на factor, прибавив correction. А вот горб так не скомпенсируешь. Таблица годится для любых датчиков, входные данные можно сразу переводить в выходные без дополнительных вычислений.
0
это что, получается? если при 1 вольте АЦП показывает 100, при 2 — 200, то это не факт что при 4 или пяти вольтах значения будут 400 и 500?
0
не факт. при 3 уже может быть 303, при 4 — 410 а при 5 — 500 ровно. Нелинейность…
0
Вроде ж атмел обещает погрешность в пределах 2 LSB
0
у меня не атмел, АЦП от микрочип, MCP3201. Возможно сказывается отсутствие буферного ОУ на входе. Стоит делитель и конденсатор 0,1мкФ.
0
А не экспериментировали с внешним ОУ?
Например у атмелов, вроде как входное сопротивление было мало, и не везде можно было использовать вход АЦП напрямую. Точно лень искать.
0
Нет, не экспериментировал, сколько разрядов составила эта нелинейность сейчас тоже не скажу. Обрабатываю данные АЦП после усреднения и пересчета соответственно делителю (автопредел до 40В). Если там больше 2разрядов, то, наверное, стоит буфер попробовать, заодно и защита входа, хотя и без защиты работает
0
многовато конечно написал )))
0
Кусочно-линейная аппроксимация может дать скачки, так что с ней нужно аккуратней быть. Можно попробовать полиномиальную характеристику — вдруг подойдет. Я уже в другой ветке писал про программу Datafit — она позволяет оценить погрешность при разных вариантах аппроксимации.
0
Я делал кусочно-линейную аппроксимацию на измерителе на PIC18F452 — весьма эффективно, правдя я аппраксимировал по предварительно отколлиброванным значениям, по критерию начало-четверть-середина-безчетверти-предел. Погрешность улучшилась в разы.
Но лучшый результат дала аппроксимация второго порядка.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.