реклама на сайте
подробности

 
 
> нестабильность показаний АЦП, нестабильность показаний АЦП
endasm
сообщение Sep 24 2012, 21:56
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673



Вообщем нужно изменять некое напряжение (для примера я взял 5в). АЦП меряет, значение преобразуется для отображения на четырехразрядном семисегментрике и выводится на него. Но два последних разряда АЦП постоянно дают разные значения (крайние правые разряды индикатора постоянно показывают разные значения, при этом частота АЦП = 15 кГц). После этого, я добавил в схему повторитель на ОУ (т.к. думал что его малое выходное значение и большое входное положительно отобразится на стабильности измерений, но не помогло - значения по прежнему скачают). Подскажите что может исправить положения дел, что бы различные помехи наводки почти не влияли на результат измерений. Видео, упрощенная схема и код прилагаются. И, кстати, до нуля вход на АЦП тоже не доходит - там где минимум 1.2в, я думаю это из-за особенностей ОУ - так как он не rail-to-rail.

Демонстрация работы



CODE
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 1000000UL
#include <util/delay.h>

int ADC_data;
unsigned char i;
unsigned char d0,d1,d2,d3;

unsigned char kod_simvola[10]= //коды цифр для семисегментного индикатора
{
0b00111111, //0
0b00000110, //1
0b01011011, //2
0b01001111, //3
0b01100110, //4
0b01101101, //5
0b01111101, //6
0b00000111, //7
0b01111111, //8
0b01101111 //9
};

//=====================ВЫВОД 4-ех ЦИФР НА СЕМИСЕГМЕНТНЫЙ ИНДИКАТОР=====================
void vivod_led(unsigned char digit0,unsigned char digit1,unsigned char digit2,unsigned char digit3)
{
cli();
unsigned char razr, digit;
DDRC=0b11111111; //PORTC0:7 подключаем к сегментам индикатора
DDRB=0b00001111; //PORTB0:3 подключаем к разрядам индикатора
for(razr=0;razr<4;razr++)
{
switch (razr)
{
case 0: digit=digit0; break;
case 1: digit=digit1; break;
case 2: digit=digit2; break;
case 3: digit=digit3; break;
}
switch (digit)
{
case 0:
PORTC=kod_simvola[0]; //выводим в порт нужную цифру
break;
case 1:
PORTC=kod_simvola[1];
break;
case 2:
PORTC=kod_simvola[2];
break;
case 3:
PORTC=kod_simvola[3];
break;
case 4:
PORTC=kod_simvola[4];
break;
case 5:
PORTC=kod_simvola[5];
break;
case 6:
PORTC=kod_simvola[6];
break;
case 7:
PORTC=kod_simvola[7];
break;
case 8:
PORTC=kod_simvola[8];
break;
case 9:
PORTC=kod_simvola[9];
break;
default: //если задан некорректный символ - выводится "_"
PORTC=0b0001000;
break;
}
if (razr==0) PORTC |=0b10000000; //зажигаем точку после первого рязряда
PORTB=1<<razr; //зажигаем нужный разряд индикатора
_delay_us(500); //менее 200 мкс - падает яркость, более 5 мс - заметно мерцание
PORTB=0<<razr; //гасим разряд индикатора
}
sei();
}

int main(void)
{
DDRA=0b00000000;
int temp; //для хранения результата преобразования АЦП

//====================ИНИЦИАЛИЗАЦИЯ ТАЙМЕРА T0===================================
TCCR0=(1<<CS00) | (1<<CS01);
/*Timer/Counter Control Register
устанавливаем коэффициент делителя таймера 64*/

OCR0=156;
/*Output Compare Register
число тактов котое будет сравниватся с числом тактов таймера*/

/*TIMSK=(1<<OCIE0);
/ *Timer/Counter Interrupt Mask Register
разрешаем прерывания по совпадению значения таймера T0 и OCR0=156* /*/

TIMSK=(1<<TOIE0);
/*Timer/Counter Interrupt Mask Register
разрешаем прерывания по переполнению таймера T0*/


//======================ИНИЦИАЛИЗАЦИЯ АЦП=======================================
ADMUX=(1<<REFS0) | (1<<ADLAR);
/*ADC Multiplexer Selection Register
REFS1:0=01 - за ИОН берем Vcc контроллера (AVcc)
MUX4:0=0000 - выбераем канал для АЦП - PORTA.0
ADLAR=1 - выравнивание результата преобразования АЦП по левому краю байтов результата*/


ADCSRA=(1<<ADEN) | (1<<ADSC) | (1<<ADPS1) | (1<<ADPS2) | (1<<ADATE);// | (1<<ADIE);
/*ADC Control and Status Register A
ADEN=1 - включаем АЦП
ADSC=1 - запускаем первое преобразование АЦП, дальше само идет автоматически
ADPS2:0=110 - делитель тактовой частоты для АЦП 1 Мгц/64 = 15.625 кГц
ADATE=1 - запускаем АЦП в режиме непрерывных последовательных преобразовний одно за другим
ADIE=0 - запрещаем прерывания по окончанию преобразования АЦП*/


SFIOR &=~(1<<ADTS0) | (1<<ADTS1) | (1<<ADTS2);
/*Special FunctionIO Register
ADTS2:0=000 - преобразование идет в непрерывном режиме с момента запуска*/


sei(); //разрешаем глобальные прерывания
while(1)
{
//ADC_data=(ADCL>>6) | (ADCH<<2); //байт ADCH всегда должен читатся последним
temp=ADC_data*0.004858*1000; //0.0049 - значение напряжение на одну ступень 4.97/1023
d3=temp%10;
temp /=10;
d2=temp%10;
temp /=10;
d1=temp%10;
temp /=10;
d0=temp%10;
vivod_led(d0,d1,d2,d3);

}
}

ISR(TIMER0_OVF_vect) //обработчик прерывания по переполнению T0
{
if(i==5)
{
ADC_data=(ADCL>>6) | (ADCH<<2); //байт ADCH всегда должен читатся последним
i=0;
}
else i++;
}


Сообщение отредактировал IgorKossak - Sep 25 2012, 06:45
Причина редактирования: [codebox] для длинного кода!!!
Go to the top of the page
 
+Quote Post
3 страниц V   1 2 3 >  
Start new topic
Ответов (1 - 38)
Snaky
сообщение Sep 24 2012, 22:30
Сообщение #2


Mute Beholder
***

Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754



Цитата(endasm @ Sep 25 2012, 07:56) *
АЦП меряет, значение преобразуется для отображения на четырехразрядном семисегментрике и выводится на него. Но два последних разряда АЦП постоянно дают разные значения (крайние правые разряды индикатора постоянно показывают разные значения, при этом частота АЦП = 15 кГц).


Установившего числа у вас никогда и не будет (разве что для самых крайних значений). Улучшением аппаратной (в основном) и программной части вы можете только приближаться к заявленным параметрам и получать все большую точность. У вас на видео видно что провода от ОУ до АЦП где-то с полметра в воздухе болтаются, чего ж вы хотели? Вот ваши несколько младших разрядов и прыгают из-за наловленного шума. Плюс контакты, разъемы, панельки... И, судя по плате, разводка аналоговых и цифровых земель скорее всего неоптимальная - плата, похоже, скорее для обучения, чем для реальной работы.

Ну и выполнять такие операции
Код
temp=ADC_data*0.004858*1000;        //0.0049 - значение напряжение на одну ступень 4.97/1023

где
Код
int temp;

как бы не совсем корректно :>

PS Кстати, угадайте сколько прилетит на вход АЦП у вас оторвется проводок идущий от потенциометра к входу "+" ОУ.


--------------------
Common sense is not so common.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 24 2012, 22:49
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(endasm @ Sep 25 2012, 00:56) *
Вообщем нужно изменять некое напряжение (для примера я взял 5в). АЦП меряет, значение преобразуется для отображения на четырехразрядном семисегментрике и выводится на него. Но два последних разряда АЦП постоянно дают разные значения (крайние правые разряды индикатора постоянно показывают разные значения, при этом частота АЦП = 15 кГц).


Ну чо, усредняйте...
Иногда ещё так делают: первое преобразование после переключения MUX-а отбрасывают (может это и не помогает).
Или возьмите 12-бит АЦП и чтоб килогерц на 100-1000 мерял.

Ну и так к слову...
Цитата(endasm @ Sep 25 2012, 00:56) *
Код
int ADC_data;

ADC_data не volatile?...странно.

Цитата(endasm @ Sep 25 2012, 00:56) *
Код
        switch (digit)
        {
            case 0:
                    PORTC=kod_simvola[0];    //выводим в порт нужную цифру
                    break;
            case 1:

Не лень такую портянку писать? Читать точно тяжело...
Код
PORTC  = (digit<10) ? (kod_simvola[digit]) : (0b0001000);


Цитата(endasm @ Sep 25 2012, 00:56) *
Код
ADC_data=(ADCL>>6) | (ADCH<<2);        //байт ADCH всегда должен читатся последним


Код
ADC_data=ADC;// компилятор сам разберётся в каком порядке ему читать (или GCC не разберётся?)

И зачем вообще эти сдвиги? Поставьте ADLAR=0.
Go to the top of the page
 
+Quote Post
endasm
сообщение Sep 25 2012, 04:31
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673



Пробовал в другом порядке считывать - после первого раза встает намертво и больше ацп не работает.

Ну а апаратно кроме как уменьшения длины проводов как-то же можно отфильтровать? И нужен ли там в действительности ОУ?
Go to the top of the page
 
+Quote Post
kovigor
сообщение Sep 25 2012, 07:33
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(endasm @ Sep 25 2012, 07:31) *
И нужен ли там в действительности ОУ?

Нужен, если выходное сопротивление источника сигнала более 10 КОм, как у вас. См в даташите раздел об АЦП и там же упрощенную схему его входного каскада ...
Go to the top of the page
 
+Quote Post
MTh
сообщение Sep 25 2012, 16:35
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 234
Регистрация: 28-02-06
Из: Иркутск
Пользователь №: 14 771



Даже в идеальном случае - младший 1-2 разряда будут плавать, никуда от этого не уйдете. Берите среднее значение за период - будет Вам счастье.
Go to the top of the page
 
+Quote Post
uriy
сообщение Sep 25 2012, 16:45
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 429
Регистрация: 30-11-05
Из: Ижевск
Пользователь №: 11 606



Вот тут описан простой фильтр http://we.easyelectronics.ru/Theory/chestn...ovoy-filtr.html дает хорошие результаты.
Go to the top of the page
 
+Quote Post
Guest_TSerg_*
сообщение Sep 25 2012, 17:08
Сообщение #8





Guests






>Вот тут описан простой фильтр...

Откровения отца Иоанна простому народу sm.gif
Go to the top of the page
 
+Quote Post
Integral
сообщение Sep 26 2012, 10:47
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 149
Регистрация: 9-08-08
Пользователь №: 39 519



Стабильность показаний АЦП зависит в первую очередь от стабильности источника опорного напряжения

Младшие разряды прыгают не просто так, прыгает напряжение на ноге АЦП, можете взять осциллограф и померять, вот как на осцилограме будет прыгать так и показания АЦП будут прыгать.

В основном все прыгает благодаря наводкам сетевой проводки 50Гц
Недавно значения показателя АЦП вывел по ЮАРТУ в терминал, сбросил все в ексель и нарисовал график, в результате получилась синусоида 50Гц

Как уменьшить влияние помех на АЦП?
Разделить аналоговую и сигнальную землю, поставить нормальный источник опорного напряжения, поставить малошумящий ОУ, экранировать провода

Иначе поднося руку к проводам будут уже другие показания

Обновляйте информацию о напряжении реже (раз в пол секунды)
В течении 0.5с делаейте 10 выборок с периодом 50мс, додавайте и делите на 10 (среднее значения напряжения за период 0.5с)
Go to the top of the page
 
+Quote Post
endasm
сообщение Sep 27 2012, 03:27
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673



А как добится полного нуля на выходе ОУ, ведь у меня там 1,3 в когда на ОУ ноль подан. Это можно сделать без применения rail to rail ОУ?
Go to the top of the page
 
+Quote Post
Tanya
сообщение Sep 27 2012, 05:34
Сообщение #11


Гуру
******

Группа: Модераторы
Сообщений: 8 752
Регистрация: 6-01-06
Пользователь №: 12 883



Цитата(endasm @ Sep 27 2012, 07:27) *
А как добится полного нуля на выходе ОУ,

Полного? Никак. Без второго питания.
Go to the top of the page
 
+Quote Post
RabidRabbit
сообщение Sep 27 2012, 05:44
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040



Ну в качестве придирки цитата из даташита:
"By default, the successive approximation circuitry requires an input clock frequency between
50kHz and 200kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the
input clock frequency to the ADC can be higher than 200kHz to get a higher sample rate."
Я бы поставил рекомендуемые 62,5 или 125кГц sm.gif
Go to the top of the page
 
+Quote Post
ReAl
сообщение Sep 27 2012, 07:53
Сообщение #13


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(uriy @ Sep 25 2012, 19:45) *
Вот тут описан простой фильтр http://we.easyelectronics.ru/Theory/chestn...ovoy-filtr.html дает хорошие результаты.
«Ну кто так строит!»™
Цитата
Y(n) = (Na*Y(n-1) + Nb*X(n)) >> 8
Нельзя в целых числах просто так «взять и поделить»
Из-за отбрасывания при делении будет предельный цикл, после какого-то шага данный фильтр остановится не дойдя до нужного значения.
В данном случае при приближении снизу (при положительной ступеньке на входе фильтра). Вот выдача простой тестовой программки (исходник ниже) для Na из указанного в статье диапазона при начальном значении фильтра 0 и значении на входе 100.
Код
Na = 239: Y stabilised at  85 after step  36
Na = 240: Y stabilised at  85 after step  38
Na = 241: Y stabilised at  83 after step  39
...
Na = 247: Y stabilised at  72 after step  48
Na = 248: Y stabilised at  69 after step  50
Т.е. при Na = 248 после 50-го шага сколько не фильтруй, а на выходе фильтра будет 69 при входе 100.
При движении сверху (отрицательная ступенька) на 60-том шаге доходит до цели 100, тут всё нормально.
Причём симметричное округление, а не отбрасывание остатка, даст только симметризацию установившегося значения, при движении снизу при Na=248 остановится на 85, при движении сверху на 116.
Можно к фиксированной точке перейти, запас разрядности соответственно уменьшит отклонение предельного значения от правильного.
В простом варианте спасти может округление в сторону цели, т.е. если Y >= X то отбрасывать остаток, а если Y < X то перед делением добавлять (делитель-1).

Вот исходник тестовой программки для PC. Поскольку в тесте ступенькой вход - константа, для входа взята не какая-то переменная X, а константа YTARGET
CODE
#include <stdio.h>
#include <stdint.h>

//Y(n) = (Na*Y(n-1) + Nb*X(n)) >> 8
// 239 <= Na <= 248, Nb = 256 - Na

enum {
NA_FROM = 239,
NA_TO = 248,
YTARGET = 100,
};

typedef int (*calcfunc_t)(int,int);

int calc_original(int y, int na)
{
return (na * y + (256-na) * YTARGET) >> 8;
}

int calc_symm(int y, int na)
{
int temp = na * y + (256-na) * YTARGET;
temp += 128;
return temp / 256;
}

int calc_to_target(int y, int na)
{
int temp = na * y + (256-na) * YTARGET;
if (y < YTARGET) temp += 255;
return temp / 256;
}

void tester(const char *header, int initial, calcfunc_t func)
{
int y;

printf("\n%s\nY initial value %d, target %d\n",
header, initial, YTARGET);

for (int na = NA_FROM; na <= NA_TO; ++na) {
printf("Na = %3d: ", na);
int y = initial;
int yprev;
int step = 0;
do {
yprev = y;
y = func(y, na);
++step;
} while( y != yprev);
printf("Y stabilised at %3d after step %3d\n", y, step);
}
}

int main()
{
tester("Original calculation code", 0, calc_original);
tester("Original calculation code", 2*YTARGET, calc_original);

tester("Symmetric rounding", 0, calc_symm);
tester("Symmetric rounding", 2*YTARGET, calc_symm);

tester("Rounding to target", 0, calc_to_target);
tester("Rounding to target", 2*YTARGET, calc_to_target);
return 0;
}

И её выдача:
CODE
Original calculation code
Y initial value 0, target 100
Na = 239: Y stabilised at 85 after step 36
Na = 240: Y stabilised at 85 after step 38
Na = 241: Y stabilised at 83 after step 39
Na = 242: Y stabilised at 82 after step 40
Na = 243: Y stabilised at 81 after step 42
Na = 244: Y stabilised at 79 after step 43
Na = 245: Y stabilised at 77 after step 45
Na = 246: Y stabilised at 75 after step 47
Na = 247: Y stabilised at 72 after step 48
Na = 248: Y stabilised at 69 after step 50

Original calculation code
Y initial value 200, target 100
Na = 239: Y stabilised at 100 after step 38
Na = 240: Y stabilised at 100 after step 40
Na = 241: Y stabilised at 100 after step 42
Na = 242: Y stabilised at 100 after step 43
Na = 243: Y stabilised at 100 after step 45
Na = 244: Y stabilised at 100 after step 47
Na = 245: Y stabilised at 100 after step 50
Na = 246: Y stabilised at 100 after step 53
Na = 247: Y stabilised at 100 after step 56
Na = 248: Y stabilised at 100 after step 60

Symmetric rounding
Y initial value 0, target 100
Na = 239: Y stabilised at 93 after step 37
Na = 240: Y stabilised at 93 after step 39
Na = 241: Y stabilised at 92 after step 40
Na = 242: Y stabilised at 91 after step 42
Na = 243: Y stabilised at 91 after step 44
Na = 244: Y stabilised at 90 after step 46
Na = 245: Y stabilised at 89 after step 48
Na = 246: Y stabilised at 88 after step 50
Na = 247: Y stabilised at 86 after step 52
Na = 248: Y stabilised at 85 after step 56

Symmetric rounding
Y initial value 200, target 100
Na = 239: Y stabilised at 107 after step 37
Na = 240: Y stabilised at 108 after step 39
Na = 241: Y stabilised at 108 after step 40
Na = 242: Y stabilised at 109 after step 42
Na = 243: Y stabilised at 109 after step 44
Na = 244: Y stabilised at 110 after step 46
Na = 245: Y stabilised at 111 after step 48
Na = 246: Y stabilised at 112 after step 51
Na = 247: Y stabilised at 114 after step 52
Na = 248: Y stabilised at 116 after step 55

Rounding to target
Y initial value 0, target 100
Na = 239: Y stabilised at 100 after step 38
Na = 240: Y stabilised at 100 after step 40
Na = 241: Y stabilised at 100 after step 42
Na = 242: Y stabilised at 100 after step 43
Na = 243: Y stabilised at 100 after step 45
Na = 244: Y stabilised at 100 after step 47
Na = 245: Y stabilised at 100 after step 50
Na = 246: Y stabilised at 100 after step 53
Na = 247: Y stabilised at 100 after step 56
Na = 248: Y stabilised at 100 after step 60

Rounding to target
Y initial value 200, target 100
Na = 239: Y stabilised at 100 after step 38
Na = 240: Y stabilised at 100 after step 40
Na = 241: Y stabilised at 100 after step 42
Na = 242: Y stabilised at 100 after step 43
Na = 243: Y stabilised at 100 after step 45
Na = 244: Y stabilised at 100 after step 47
Na = 245: Y stabilised at 100 after step 50
Na = 246: Y stabilised at 100 after step 53
Na = 247: Y stabilised at 100 after step 56
Na = 248: Y stabilised at 100 after step 60
Конечно, если считать во всяких электронных таблицах или в самописных программах в плавучке, то этого не видно.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 27 2012, 08:28
Сообщение #14


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(ReAl @ Sep 27 2012, 10:53) *
«Ну кто так строит!»™
Можно к фиксированной точке перейти, запас разрядности соответственно уменьшит отклонение предельного значения от правильного.

Можно просто хранить Y, сдвинутое <<8, т.е. в виде 0xmmff (целая часть, дробная часть).
И входное значение X сдвинуть <<8.
А потом уже оба складывать в своей пропорции.
А на вывод выдавать только целую часть Y, т.е. сдвинуть >>8.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Sep 27 2012, 08:47
Сообщение #15


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(ViKo @ Sep 27 2012, 11:28) *
Можно просто хранить Y, сдвинутое <<8, т.е. в виде 0xmmff (целая часть, дробная часть).
Ну так это и есть переход к фиксированной точке 8.8
Но большой запас разрядности плюс заметная фильтрация уже выталкивают в 32 бита даже при 8-битных входных значениях. Так что надо смотреть по месту, где-то я комбинировал и запас разрядности, и проверку куда округлять.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 27 2012, 08:57
Сообщение #16


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(ReAl @ Sep 27 2012, 11:47) *
Ну так это и есть переход к фиксированной точке 8.8
Но большой запас разрядности плюс заметная фильтрация уже выталкивают в 32 бита даже при 8-битных входных значениях. Так что надо смотреть по месту, где-то я комбинировал и запас разрядности, и проверку куда округлять.

Для 8-разрядного входного числа и 8-разрядных коэффициентах размерности 8.8 хватит гарантированно. Можно проверить на вашей же программе. А промежуточные вычисления делать 24-битовыми. XX.XX * .NN = ZZ.ZZZZ

upd. добавил подчеркнутое
Go to the top of the page
 
+Quote Post
drvlas
сообщение Sep 27 2012, 09:39
Сообщение #17


Участник
*

Группа: Участник
Сообщений: 50
Регистрация: 3-09-10
Пользователь №: 59 263



Цитата(ReAl @ Sep 27 2012, 10:53) *
«Ну кто так строит!»™
Нельзя в целых числах просто так «взять и поделить»
...
Конечно, если считать во всяких электронных таблицах или в самописных программах в плавучке, то этого не видно.

Ну, если это камень в огород автора той заметки на Easyelectronics, то отвечу. Автор пользуется описанным подходом с середины 80-х и обычно как раз в целочисленной арифметике. Так что эффект потери точности при делении ему известен. И он легко устраняется сохранением неделенного результата.
В обсуждении той заметки была приведена даже реализация фильтра на Си.
Код
int filter(int x, int Na, int k){
static int y = 0, z = 0;
z += (x — y);
return y = Na * z >> k;
};

Увы, переделка статьи, в которой должен был быть учтен этот пробел, была отложена.
Так что спасибо за напоминание! Доработаем-с!
Go to the top of the page
 
+Quote Post
xemul
сообщение Sep 27 2012, 09:59
Сообщение #18



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Даже с сохранением неделённого результата так
Код
return y = (Na * z + (1<<(k-1))) >> k;

будет корректнее.
Go to the top of the page
 
+Quote Post
drvlas
сообщение Sep 27 2012, 10:20
Сообщение #19


Участник
*

Группа: Участник
Сообщений: 50
Регистрация: 3-09-10
Пользователь №: 59 263



Да, конечно, симметричное округление. Это правильно.
Но я обычно в промежуточных вычислениях работаю с запасом по разрешающей способности. Поэтому там округлением не занимаюсь. А только в конце, может быть, проделаю такое добавление половинки единицы дискретности.
Например, с АЦП идет много разрядов, младшие пляшут (собсно, зачем и усредняем), мы пускаем все это в обработку, не заботясь о мелочи, полразряда. А когда уж на индикатор выводится значение, которое должно быть стабильным, которое имеет определенную дискретность (не взятую с потолка) - вот тогда и есть смысл прибавить половинку.

В статье поправил. Еще раз спасибо коллеге ReAl. Да, и оговорился там, что от диапазона входных величин x, Na и k зависит и выбор z. В указанном примере лучше сразу объявить long z. Что скажете?

Сообщение отредактировал drvlas - Sep 27 2012, 10:21
Go to the top of the page
 
+Quote Post
xemul
сообщение Sep 27 2012, 10:32
Сообщение #20



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(drvlas @ Sep 27 2012, 14:20) *
Что скажете?

Скажу, что при равномерном распределении (k-1)-го разряда методическая погрешность (y = Na * z >> k) за N вызовов filter() составит N*(1<<(k-1))/2.

UPD: нет, меньше, но лень предел считать в уме.
Go to the top of the page
 
+Quote Post
Tanya
сообщение Sep 27 2012, 10:48
Сообщение #21


Гуру
******

Группа: Модераторы
Сообщений: 8 752
Регистрация: 6-01-06
Пользователь №: 12 883



Цитата(xemul @ Sep 27 2012, 14:32) *
Скажу...

Я тоже хочу сказать, что как бы ни были (при)увлекательны формулы и числа, надо сначала посмотреть на реальную правду в глазах.
Если имеется наводка, то от нее нужно избавляться в зародыше, чтобы потом не морочиться с числами.
Вот если есть наводка, а автор хочет измерять от нуля, то вблизи нуля никакие числовые фильтры не помогут.
И вблизи максимума... Поэтому нужно отфильтровать на входе аналоговым фильтром и сместить и сжать шкалу.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 27 2012, 11:19
Сообщение #22


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Tanya @ Sep 27 2012, 13:48) *
вблизи нуля никакие числовые фильтры не помогут.
И вблизи максимума...

Например, берем скользящее среднее. Если встречаются помехи-импульсы относительно сигнала-нуля, они тоже усреднятся. Не вижу причин для беспокойства. Ну, приподнимется чуть-чуть результат. Так надо же соображать, чтобы диапазон измеряемого сигнала (вместе с помехами, мы же не детектор-выпрямитель проектируем) укладывался в диапазон АЦП.
Go to the top of the page
 
+Quote Post
drvlas
сообщение Sep 27 2012, 11:29
Сообщение #23


Участник
*

Группа: Участник
Сообщений: 50
Регистрация: 3-09-10
Пользователь №: 59 263



Цитата(Tanya @ Sep 27 2012, 13:48) *
Если имеется наводка, то от нее нужно избавляться в зародыше, чтобы потом не морочиться с числами.

И верно, и нет.
Да, нужно подходить комплексно и не стараться вытянуть ЦОС грубые недоработки в проектировании платы.
Нет, ибо с числами можно не морочиться, а значительно улучшить результаты. Весь мир так делает. Почему нам отказываться?

Давайте конкретнее.
Цитата(Tanya @ Sep 27 2012, 13:48) *
Вот если есть наводка, а автор хочет измерять от нуля, то вблизи нуля никакие числовые фильтры не помогут.
Вблизи нуля помогут. Нужно правильно выбирать диапазон работы АЦП, вот и все. Впрочем, коллега ViKo уже сказал об этом.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 27 2012, 11:54
Сообщение #24


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Можно и аналогию из аналоговой схемотехники привести. Если помехи у нас есть ниже нуля скачут, то фильтром на ОУ, запитанным от положительного питания, мы их тоже не отфильтруем.
Go to the top of the page
 
+Quote Post
endasm
сообщение Sep 27 2012, 13:44
Сообщение #25


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673



А применение rail to rail ОУ даст мне на 10 битном АЦП полный ноль и полные 5 v ? ( шаг АЦП 0,0048 v)

Сообщение отредактировал endasm - Sep 27 2012, 13:47
Go to the top of the page
 
+Quote Post
ReAl
сообщение Sep 27 2012, 17:09
Сообщение #26


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(drvlas @ Sep 27 2012, 12:39) *
В обсуждении той заметки была приведена даже реализация фильтра на Си.
...
Увы, переделка статьи, в которой должен был быть учтен этот пробел, была отложена.
Да вот я как-то, пардон, комментарии читать начал, но далеко не зашёл :-)
«Увы, ... отложена» близко и понятно :-(

Этот фильтр дотягивать будет и (с учётом замечания по симметризации округления) явно лучше.
Только такое впечатление, что, в терминологии исходной заметки, в нём не Na должно быть, а Nb.
Точнее, и ни то, и ни другое, так как фильтр уже другой, но Nb (малое по сравнению с делителем) по смыслу ближе.
По крайней мере если брать по статье Na=248 (30-кратное превышение влияния фильтрованного значения перед новым отсчетом), то в этот фильтр никак нельзя 248 ставить, он с таким коэффициентом при ступеньке даже в сотни квантов в несколько прыжков выйдет на заданное значение, а не в многие десятки.


Цитата(endasm @ Sep 27 2012, 16:44) *
А применение rail to rail ОУ даст мне на 10 битном АЦП полный ноль и полные 5 v ? ( шаг АЦП 0,0048 v)
Смотрите документацию на ОУ. RR может считаться уже когда он, скажем, милливольт пятдесят или сто от шины работает. А не пять.
Да и свой сигнал до нуля и опорного я чтараюсь и не рассчитывать, у АЦП свои ошибки есть. Если надо, подставку небольшую делаю. В том числе чтобы шумы/наводки при ограничении об шину не давали смещение сигнала после фильтрации.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
drvlas
сообщение Sep 27 2012, 18:04
Сообщение #27


Участник
*

Группа: Участник
Сообщений: 50
Регистрация: 3-09-10
Пользователь №: 59 263



Цитата(ReAl @ Sep 27 2012, 20:09) *
Да вот я как-то, пардон, комментарии читать начал, но далеко не зашёл :-)
"но далеко не зашел" близко и понятно sm.gif

Цитата(ReAl @ Sep 27 2012, 20:09) *
Только такое впечатление, что, в терминологии исходной заметки, в нём не Na должно быть, а Nb.
Ай-ай-ай! Это была ошибка. Уже устранил. Огромное спасибо!
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 28 2012, 05:13
Сообщение #28


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(drvlas @ Sep 27 2012, 12:39) *
Так что эффект потери точности при делении ему известен. И он легко устраняется сохранением неделенного результата.
В обсуждении той заметки была приведена даже реализация фильтра на Си.
...

То есть, вместо хранения Y в форме целой и дробной частей (которые, в принципе, можно обе использовать для выдачи - получаем увеличение разрядности, о котором говорится на каждом микроконтроллерном сайте) вы будете хранить Y (целую часть? или не хранится?) и Z (целую и дробную части). И в чем выигрыш? В уменьшении умножений - вместо двух - одно? Так если брать Nb как степень двойки, можно одними сдвигами и сложениями обойтись.
А именно, например для Nb = 16 - из Y вычитаем 1/16 часть, а X уменьшаем в 16 раз, и добавляем к Y.
Go to the top of the page
 
+Quote Post
drvlas
сообщение Sep 28 2012, 06:14
Сообщение #29


Участник
*

Группа: Участник
Сообщений: 50
Регистрация: 3-09-10
Пользователь №: 59 263



Цитата(ViKo @ Sep 28 2012, 08:13) *
То есть, вместо хранения Y в форме целой и дробной частей (которые, в принципе, можно обе использовать для выдачи - получаем увеличение разрядности, о котором говорится на каждом микроконтроллерном сайте) вы будете хранить Y (целую часть?) и Z (целую и дробную части). И в чем выигрыш?

Спасибо, что заметили: сохранять Y вовсе не обязательно. Я поленился еще раз переделывать код, так как это мелочь, что она объявлена статической. Если уж Вам очень хочется, чтобы все используемые переменные имели одинаковую размерность, то считайте, что у Z есть целая и дробная часть. Мой скромный, но очень практический опыт работы с целочисленной арифметикой говорит о том, что нужно хорошенько разбираться с размерностью на этапе проектирования математики. Когда модель, формулы построены, то в реализации уже не так важно, где стоит запятая (точка). Поэтому я считаю все переменные целыми (как их и обрабатывает МК) и редко говорю "фиксированная точка", а чаще "целочисленная арифметика".

Пример: умножаем ЧИСЛО1 * ЧИСЛО2. Оба целые однобайтные. Результат ЧИСЛО3 - двухбайтное целое. Прекрасно.
ЧИСЛО1 - однобайтовое целое
ЧИСЛО2 - однобайтовое целое
ЧИСЛО3 - двухбайтовое целое
Можно объявить вообще все эти числа ИНТами или ЛОНГами. Никаких запятых.

Теперь нам захотелось результат иметь такого же масштаба, что и ЧИСЛО1. Хорошо, можете считать, что у ЧИСЛА2 запятая отделяет 8 бит дробной части. Тогда
ЧИСЛО1 - честно однобайтовое целое
ЧИСЛО2 - однобайтовое дробное
ЧИСЛО3 - двухбайтовое с целой и дробной частью.
Как на мой взгляд, то первый вариант проще для восприятия. Но на вкус и цвет...

Цитата(ViKo @ Sep 28 2012, 08:13) *
Так если брать Nb как степень двойки, можно одними сдвигами и сложениями обойтись.
А именно, например для Nb = 16 - из Y вычитаем 1/16 часть, а X уменьшаем в 16 раз, и добавляем к Y.

Вы немного не дочитали статью sm.gif Она, собственно, посвящена тому, как можно легко и просто найти Nb по заданным характеристикам фильтра (а именно: по времени отклика на ступенчатое воздействие). Поэтому уж такой свободы в выборе Nb у нас нет. Ну, частный случай может быть, что Nb = 16, но я считал более важным обеспечить Na+Nb=256 или иная степень двойки, чтобы деления не было.

Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 28 2012, 06:20
Сообщение #30


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(drvlas @ Sep 28 2012, 09:14) *
Вы немного не дочитали статью sm.gif Она, собственно, посвящена тому, как можно легко и просто найти Nb по заданным характеристикам фильтра (а именно: по времени отклика на ступенчатое воздействие). Поэтому уж такой свободы в выборе Nb у нас нет. Ну, частный случай может быть, что Nb = 16, но я считал более важным обеспечить Na+Nb=256 или иная степень двойки, чтобы деления не было.

Я не читал вдумчиво, но ваш путь выбора фильтра разглядел. Однако, ради простоты фильтра я не стал бы заморачиваться получением точного времени отклика. Уверен, в большинстве случаев так и надо поступать.
Я пишу не про форму представления числа. А про лишнюю сущность - переменную Z.
Na + Nb = 256 можно (и нужно) обеспечивать и при Nb - степени двойки. Na мы вообще не будем использовать, я написал выше, как это получается.
Go to the top of the page
 
+Quote Post
muravei
сообщение Sep 28 2012, 08:21
Сообщение #31


Гуру
******

Группа: Свой
Сообщений: 2 538
Регистрация: 13-08-05
Пользователь №: 7 591



Цитата(endasm @ Sep 27 2012, 16:44) *
А применение

Попробуйте "скользящее среднее" кратно 50 Гц , думаю, сильно облегчит вашу участь.
Go to the top of the page
 
+Quote Post
endasm
сообщение Sep 28 2012, 09:41
Сообщение #32


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673



Я тогда попробую поставить такой rail-to-rail ОУ что бы у него диапазон выходных знечений был такой что бы он по краям обрезал менее 5 мв. Скоро допилю програмный фильтр и выложу результат.
Go to the top of the page
 
+Quote Post
Tanya
сообщение Sep 28 2012, 10:59
Сообщение #33


Гуру
******

Группа: Модераторы
Сообщений: 8 752
Регистрация: 6-01-06
Пользователь №: 12 883



Цитата(endasm @ Sep 28 2012, 13:41) *
Я тогда попробую поставить такой rail-to-rail ОУ что бы у него диапазон выходных знечений был такой что бы он по краям обрезал менее 5 мв.

Если найдете такой, - срочно сообщите.
И, по ходу, по входу.
Go to the top of the page
 
+Quote Post
AndreyVN
сообщение Sep 29 2012, 17:02
Сообщение #34


Знающий
****

Группа: Свой
Сообщений: 754
Регистрация: 29-06-06
Из: Volgograd
Пользователь №: 18 458



Пользую с Мегами ОУ AD8602 (Rail-to-Rail), никаких "подрезаний" не обнаружено, работает от абсолютного нуля до питания (верх не проверял). Шум в 1 бит случается, но довольно редко, может до 1000 измерений идеально держать величину с точностью до МЗР.

У Rail-to-Rail ОУ, вроде, внутри схема вольтодобавки на переключаемых конденсаторах, с чего им 5mV подрезать? Или я не прав?

Питание 5В стабилизируется разными стабилизаторами для цифры и для аналоговой части и АЦП (MC78L05ACD), оно-же - опора с RC фильтром. Ну, само собой, земляной регион, разводка подальше от цифровых шин, конденсатооров по шинам питания побольше.

К стати, вычитываю данные вот так:
adc1 = ADCL; //Читаем результат преобразования сначала младший
adc2 = ADCH; //затем старший
V = (adc1 + adc2*256)*0.125;
И еще, не забыть включить ADC Nois Reduction Mode (регистр MCUCR, биты SM2,SM1,SM0).

Работаю в режиме одиночного преобразования, которое запукается от таймера, никакой стат обработки не использую.
К стати, у меня при оцифровке выше 5 кГц начинает падать точность, но, это, возможно, личные заморочки.
Go to the top of the page
 
+Quote Post
rx3apf
сообщение Sep 29 2012, 19:00
Сообщение #35


Гуру
******

Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047



Вольтодобавка в ОУ - это больше похоже на кошмарный сон, приснившийся под утро. Бывает такое, знаю по себе. Я даже готов поверить, что такие изделия реально есть в природе, но это не типовое решение, точно. Потом, R2R это хорошо, конечно, но если мы работаем от Vcc в качестве опоры, то и этого в общем случае для полной шкалы недостаточно (ошибка смещения может быть больше трех единиц. Noise reduction - а sleep-то используете ?

Ну и по теме - вообще получить мерцание больше 1LSB при 10-битном ADC это тоже надо постараться. Даже на макетной плате с проводами....
Go to the top of the page
 
+Quote Post
Myron
сообщение Sep 29 2012, 20:45
Сообщение #36


Профессионал
*****

Группа: Свой
Сообщений: 1 849
Регистрация: 6-02-05
Пользователь №: 2 451



Цитата(AndreyVN @ Sep 29 2012, 12:02) *
У Rail-to-Rail ОУ, вроде, внутри схема вольтодобавки на переключаемых конденсаторах, с чего им 5mV подрезать? Или я не прав?

В этом ОУ вольтодобавки еще нет и "подрезает" он по выходу исправно (см. пристегнутый файл).
У него относительно хороши входные характаристики за счет N- и P- MOS комбинированного входного дифф каскада. Но про этом появляется другая болезнь - ступенька в смещении и ступенька во входном токе. И, если с первой проблемой можно жить (иногда) за счет глубокой ОС, то ступенька в токе в середине уровня входного сигнала может привести к головной боли при использовании достаточно больших резисторов на ходе (например, в фильтрах и т.д.)
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
drvlas
сообщение Sep 29 2012, 20:58
Сообщение #37


Участник
*

Группа: Участник
Сообщений: 50
Регистрация: 3-09-10
Пользователь №: 59 263



Несколько старнно то, что автор не хочет пойти простым путем. Я имею в виду обычную двухполярную схему питания ОУ. Получить ее не сложно, хоть с того же MAX232 (пример схемы).

Но вообще-то все зависит от задачи. Если нужно задавать что-то потенциометром, а хочется его от упора до упора крутить, так его снизу можно ограничить резистором, чтобы не доходил до "земди", равно как и сверху, чтобы запас от опоры был.

Так что, ИМХО, мы тут копья перья ломаем зря. Пусть автор определится с хотелкой.
Go to the top of the page
 
+Quote Post
endasm
сообщение Oct 1 2012, 05:23
Сообщение #38


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673



Хорошая идея, но MAX232 довольно дорогая, если бы не это то я бы наверняка использовал бы её.
Go to the top of the page
 
+Quote Post
drvlas
сообщение Oct 1 2012, 05:46
Сообщение #39


Участник
*

Группа: Участник
Сообщений: 50
Регистрация: 3-09-10
Пользователь №: 59 263



Цитата(endasm @ Oct 1 2012, 08:23) *
Хорошая идея, но MAX232 довольно дорогая, если бы не это то я бы наверняка использовал бы её.
Ну, если речь идет о разовом изделии, то вопрос пары баксов кагбэ не вопрос, ИМХО. А в серии можно поискать и другие решения. Я назвал то, что на поверхности. Просто смысл убиваться в 5 мВ возле "рельсов" - сомнительно, по сравнению с классическим двухполярным (и даже не обязательно симметричным) питанием.
Да, сам себе нечаянно подсказал: если поставить источник питания всей системы на 5 В, и создать землю на диоде (0,7 В или добавить Шоттки для вольта), то "минус" этого источника будет около -1 В относительно земли. Вот и не надо так переживать за последние 5 мВ, запитываешь ОУ от -1...+5 В.
Честно скажу, сам так не делал. Но почему нет?

UPD
Вот изобразил, как это легко получить. Микроконтроллерная часть питается просто от 5В и "земли", а аналоговая - от 5В и источника "минус 700 мВ" на диоде. И, если ОУ хоть в какой-то мере rail-to rail (уж не имеет значения, до 5 мВ или до 50 мВ от земли) - все работает чики-пики.
В реальной схеме может еще понадобится запустить немного току в диод (резистор R1), если ток потребления МК очень прыгает. Дело в том, что диоду нужно немного выйти на режим - тогда и его напряжение более стабильно, и его динамическое сопротивление значительно падает (то есть "выходное сопротивление" источника минус 700 мВ)

Прикрепленное изображение


Сообщение отредактировал drvlas - Oct 1 2012, 08:30
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 18:58
Рейтинг@Mail.ru


Страница сгенерированна за 0.01798 секунд с 7
ELECTRONIX ©2004-2016