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

 
 
> Усреднение вычислений АЦП
Wantcan
сообщение Jan 10 2009, 05:35
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 11-12-08
Из: Earth
Пользователь №: 42 366



Подскажите хороший алгоритм для усреднения вычислений АЦП,я сделал так-
Код
// Read the 8 most significant bits
// of the AD conversion result
unsigned char read_adc(unsigned char adc_input){
ADMUX=adc_input|ADC_VREF_TYPE;
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCH;}

while (1){....

   ta++;if(ta==21)ta=0;
   tempADC=(read_adc(0)/5);
   tempADC1=tempADC+(read_adc(0)/5);                  
   if(ta==20)temp=tempADC1/2;tempADC=0;tempADC1=0;
т.е. показывать на индикаторе среднее число из 20 вычислений,но все равно не так сглаженно получается.
Go to the top of the page
 
+Quote Post
3 страниц V   1 2 3 >  
Start new topic
Ответов (1 - 42)
rvk
сообщение Jan 10 2009, 05:57
Сообщение #2


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

Группа: Свой
Сообщений: 165
Регистрация: 13-05-06
Из: Камышин
Пользователь №: 17 067



Конечно не сглаженно, потому что Вы сняв двадцать значений стираете и начинаете набирать по новой.
И кстати складываете Вы двадцать значений, а делите только на два. Если это такая фишка, чтобы результат в итоге умножить на два,
тогда понятно.
И деление на 5 я провожу в самом конце, всего один раз над переменной temp. Это сделает более точными вычисления.

Поэтому у Вас есть усреднение не скользящее, а среднее на каждые отдельно взятые двадцать значений. Простой способ сделать скользящее, это вычитать самое раннее и прибавлять последнее. Но при этом обязательно накопится ошибка вычислений. Продвинутый способ, как писал в другой ветке resident, это хранить все двадцать последних значений в массиве, и делать среднее по нему, примерно вот так:
unsigned char tempData[20];
unsigned char ta=0;
unsigned char i;
unsigend short temp;

while (1){....

ta++;if(ta==20) ta=0;
tempData[ta]=read_adc(0);// деление на 5 перенесено в расчет temp

temp = 0;
for(i=0;i<20;i++){
temp += tempData[i];
}
temp =temp/100; // 20*5

}

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

Сообщение отредактировал rvk - Jan 10 2009, 06:04
Go to the top of the page
 
+Quote Post
Wantcan
сообщение Jan 10 2009, 06:12
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 11-12-08
Из: Earth
Пользователь №: 42 366



Цитата
И кстати складываете Вы двадцать значений, а делите только на два
-по другому почему-то не получилось-показания выходят из диапазона.Ваш пример попробую,но for не желательно(может даже не допустимо),т.к. этот алгоритм находится внутри программного генератора,for даст задержку и повлияет на частоту генератора,но попробую и отпишусь,что получилось.
Go to the top of the page
 
+Quote Post
rvk
сообщение Jan 10 2009, 06:19
Сообщение #4


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

Группа: Свой
Сообщений: 165
Регистрация: 13-05-06
Из: Камышин
Пользователь №: 17 067



Ну используйте вместо for вложенный цикл while:

temp = 0;
i=20;
while(i--){
temp += tempData[i];
}

И кстати, поскольку temp имеет тип unsogned short, никаких переполнений быть не должно.
Потому что даже максимальное значение АЦП 255*100= 25500 все равно меньше
65536, поэтому можно смело все складывать, а затем найти среднее.
Go to the top of the page
 
+Quote Post
Alex11
сообщение Jan 10 2009, 09:27
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 2 106
Регистрация: 23-10-04
Из: С-Петербург
Пользователь №: 965



Есть еще один способ получить скользящее среднее. Инициализация:
unsigned int sum, Result;
#define shift 3 // от 1 до 7 при Ваших условиях
sum = 0;
На каждое измерение:
Result = sum >> shift;
sum = sum - Result + read_adc(0);
В зависимости от shift получается различная степень усреднения и разная скорость выхода на устоявшееся значение.
Go to the top of the page
 
+Quote Post
Wantcan
сообщение Jan 10 2009, 10:52
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 11-12-08
Из: Earth
Пользователь №: 42 366



С последним способом у меня не получилось-цифры скачут, а вот так-тоже интересно-
Код
ta++;if(ta==100) ta=0;
   tempData[ta]=read_adc(0);
   tempADC=0;  
   for(a=0;a<100;a++){
   tempADC+=tempData[a];}
   temp=tempADC/500;
-как нагрузку подключаю-цифры на индикаторе пробегают от нуля до нормального значения,после отключения-обратно до нуля.
Go to the top of the page
 
+Quote Post
Herz
сообщение Jan 10 2009, 11:20
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Цитата(Alex11 @ Jan 10 2009, 11:27) *
Есть еще один способ получить скользящее среднее. Инициализация:
unsigned int sum, Result;
#define shift 3 // от 1 до 7 при Ваших условиях
sum = 0;
На каждое измерение:
Result = sum >> shift;
sum = sum - Result + read_adc(0);
В зависимости от shift получается различная степень усреднения и разная скорость выхода на устоявшееся значение.

Здесь, похоже, кое-что упущено. Деление, например, или сдвиг в последней операции. Иначе алгоритм предполагает нарастание результата с различной скоростью, зависящей от shift.
Go to the top of the page
 
+Quote Post
rvk
сообщение Jan 10 2009, 11:23
Сообщение #8


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

Группа: Свой
Сообщений: 165
Регистрация: 13-05-06
Из: Камышин
Пользователь №: 17 067



Не забывайте только про переполнение temp. Если значение АЦП будет больше 65535/500 = 131, то произойдет переполнение
переменной temp и значения будут неверные. Проще говоря такая формула работает если значения АЦП были меньше 0x80.
А то, что от нуля до нормального значения, так и должно быть, ведь для первое значение делится на 100, остальные значения
ведь пустые. Второе значение складывается с первым и оба делятся на 100 и т.д. пока не будет заполнен весь массив.
Чтобы с первого значения было все верно, нужно отследить весь массив до заполнения и делить пропорционально
заполнению. Но это уже мелочи.
Go to the top of the page
 
+Quote Post
rezident
сообщение Jan 10 2009, 11:34
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(rvk @ Jan 10 2009, 16:23) *
Чтобы с первого значения было все верно, нужно отследить весь массив до заполнения и делить пропорционально заполнению.
Совсем не обязательно. Достаточно при первом обращении к фильтру проинициализировать весь массив не нулями, а этим самым первым значением. Это для случая фильтрации типа "скользящее среднее" конечно же.
Go to the top of the page
 
+Quote Post
Demeny
сообщение Jan 10 2009, 18:33
Сообщение #10


Знающий
****

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



Цитата(rvk @ Jan 10 2009, 08:57) *
Продвинутый способ, как писал в другой ветке resident, это хранить все двадцать последних значений в массиве, и делать среднее по нему, примерно вот так:
...........

Для усреднения по последним 20 значениям совсем необязательно хранить последние 20 значений в массиве, зачем расходовать память и ресурсы процессора, чтобы их каждый раз суммировать. А если нужно будет усреднять по 10000 значений ?
Вот простой способ получать усреднённое значение каждый раз при получении текущего измеренного значения:
Код
T_average = T_average + (T_current - T_average) / 20.0

где T_average - среднее значение на данный момент времени, T_current - мгновенное измеренное значение, снятое, например, с АЦП в текущий момент времени.
Этот пример НЧ-фильтра измерений практически эквивалентен усреднению последних 20 значений. Однако здесь число усреднений (20) необязательно может быть целым значением. Вообще говоря, в этой формуле число 20.0 является постоянной времени фильтра, которая вкупе с периодом измерений определяет скорость реакции (инертность) этого фильтра на резкие изменения входных измеряемых величин.


--------------------
Сделано в Китае. Упаковано в России.
Go to the top of the page
 
+Quote Post
rezident
сообщение Jan 10 2009, 18:55
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Demeny @ Jan 10 2009, 23:33) *
Этот пример НЧ-фильтра измерений практически эквивалентен усреднению последних 20 значений.
Вообще-то это пример фильтра EMA (экспоненциальное скользящее среднее), а не SMA (простое скользящее среднее). В общем виде EMA выглядит как рекурсия Y(i+1)=Y(i)+(X(i)–Y(i))*K, где K=2/(N+1), Y(i+1) выходное значение фильтра, Y(i) - предыдущее выходное значение фильтра, X(i) - значение текущего отсчета. N имеет тот же смысл, что и "тау" RC-цепочки. Отличие EMA от SMA еще в том, что EMA это фильтр с БИХ, а SMA - с КИХ.
Go to the top of the page
 
+Quote Post
rvk
сообщение Jan 10 2009, 19:02
Сообщение #12


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

Группа: Свой
Сообщений: 165
Регистрация: 13-05-06
Из: Камышин
Пользователь №: 17 067



Цитата(Demeny @ Jan 10 2009, 21:33) *
Вот простой способ получать усреднённое значение каждый раз при получении текущего измеренного значения:
Код
T_average = T_average + (T_current - T_average) / 20.0

где T_average - среднее значение на данный момент времени, T_current - мгновенное измеренное значение, снятое, например, с АЦП в текущий момент времени.

Вот пример в числах есть 10 чисел. Берем скользящее среднее 5 значений:
11, 9, 11, 9, 10, 12, 11, 7, 8, 5,
среднее____ 10, 10.4, 10.52, 9.816, 9.4528, 8.56224 Это по Вашей формуле

А это по массиву из последних набранных пяти значений:
11, 9, 11, 9, 10, 12, 11, 7, 8, 5
среднее____ 10, 10.2, 10.6, 9.8, 9.6, 8.6

Поэтому эти формулы какие угодно, только не взаимозаменяемые. И Ваша формула не проще,
она просто другая.

Сообщение отредактировал rvk - Jan 10 2009, 19:08
Go to the top of the page
 
+Quote Post
Demeny
сообщение Jan 10 2009, 19:42
Сообщение #13


Знающий
****

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



Цитата(rezident @ Jan 10 2009, 21:55) *
Вообще-то это пример фильтра EMA (экспоненциальное скользящее среднее), а не SMA (простое скользящее среднее). В общем виде EMA выглядит как рекурсия Y(i+1)=Y(i)+(X(i)–Y(i))*K, где K=2/(N+1), Y(i+1) выходное значение фильтра, Y(i) - предыдущее выходное значение фильтра, X(i) - значение текущего отсчета. N имеет тот же смысл, что и "тау" RC-цепочки. Отличие EMA от SMA еще в том, что EMA это фильтр с БИХ, а SMA - с КИХ.

Всё это верно, я и не сомневался в Вашей компетентности в этом вопросе. Автор топика просил алгоритм усреднения значений АЦП, поэтому я предложил практическую формулу, не вдаваясь в теорию фильтров, импульсные характеристики, оператор Лапласа и т. п. Эта формула неоднократно мною проверена и прекрасно работает, например, в системах управления газотурбинными двигателями.
Конечно, численно она отличается от простого усреднения, но практически ведёт себя точно также и позволяет избежать хранения и суммирования последних N измерений, что особенно актуально для систем на маломощных вычислителях с ограниченными ресурсами (AVR, PIC).


--------------------
Сделано в Китае. Упаковано в России.
Go to the top of the page
 
+Quote Post
rezident
сообщение Jan 10 2009, 20:26
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Demeny @ Jan 11 2009, 00:42) *
Конечно, численно она отличается от простого усреднения, но практически ведёт себя точно также
Да как же они могут вести себя одинаково, если у них и ФЧХ и ПХ разные!?
Go to the top of the page
 
+Quote Post
777777
сообщение Jan 11 2009, 07:46
Сообщение #15


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

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(Wantcan @ Jan 10 2009, 08:35) *
Подскажите хороший алгоритм для усреднения вычислений АЦП

Если показания АЦП дрожат, то нужно думать не о том, как их отфильтровать, а о том, как устранить источник помех. А для этого нужно совсем немного, как-то:

- разводить земли и питание широкими проводниками, желательно чтобы эти проводники не прыгали с одного слоя на другой, а если нужно, то переход делать через большие переходные отверстия.
- подводить ко всем 8 ногам контроллера, а для опорного желательно дополнительный RC-фильтр
- в непосредственной близости от него должно быть хотя бы две пары конденсаторов по питанию (электролит+керамика)
- если в схеме есть сильнопотребляющие элементы (светодиоды, например), то землю от них до источника вести отдельным проводником, чтобы падение напряжения от скачков тока не вызывало скачков напряжения на земле
- и т.д.

Я бы еще понял, если бы АЦП было 14-16 разрядным, но я не представляю, как надо изуродовать схему, чтобы дрожало 10-разрядное АЦП - чтобы там получить стабильные значения не требуется особо напрягаться.
Go to the top of the page
 
+Quote Post
Demeny
сообщение Jan 11 2009, 07:46
Сообщение #16


Знающий
****

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



Цитата(rezident @ Jan 10 2009, 23:26) *
Да как же они могут вести себя одинаково, если у них и ФЧХ и ПХ разные!?

В первом посте автор топика обозначил задачу - "показывать на индикаторе среднее значение", для этой задачи различия КИХ и БИХ фильтров несущественны - оба являются инерционным звеном и справляются с поставленной задачей. Приведённая мной формула экспоненциального скользящего среднего позволяет обойтись без хранения массива измеренных значений и их пересуммирования на каждом цикле измерения.
Может быть, автору окажется полезной статья "Выбор типа скользящих средних" , которую я прикрепил к сообщению. Кстати, в ней на 52 странице приведены импульсные характеристики различных типов усреднения. Сравнив графики б) и г) легко убедиться, что ИХ простого взвешенного усреднения и экспоненциального весьма схожи.
Прикрепленные файлы
Прикрепленный файл  50_55.pdf ( 945.56 килобайт ) Кол-во скачиваний: 437
 


--------------------
Сделано в Китае. Упаковано в России.
Go to the top of the page
 
+Quote Post
777777
сообщение Jan 11 2009, 07:53
Сообщение #17


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

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(rezident @ Jan 10 2009, 21:55) *
Вообще-то это пример фильтра EMA (экспоненциальное скользящее среднее), а не SMA (простое скользящее среднее). В общем виде EMA выглядит как рекурсия Y(i+1)=Y(i)+(X(i)–Y(i))*K, где K=2/(N+1), Y(i+1) выходное значение фильтра, Y(i) - предыдущее выходное значение фильтра, X(i) - значение текущего отсчета. N имеет тот же смысл, что и "тау" RC-цепочки.

Смысл может и тот же, а насчет численного значения я сильно сомневаюсь. Чтобы получить фильтр с постоянной времени tau, коэффициент вычисляется по формуле K = 1 - exp(-T/tau), где T - период следования входных отсчетов.
Go to the top of the page
 
+Quote Post
Microwatt
сообщение Jan 11 2009, 09:03
Сообщение #18


Гуру
******

Группа: Почетный участник
Сообщений: 6 851
Регистрация: 25-08-08
Из: Запорожье
Пользователь №: 39 802



Цитата(777777 @ Jan 11 2009, 11:53) *
Смысл может и тот же, а насчет численного значения я сильно сомневаюсь. Чтобы получить фильтр с постоянной времени tau, коэффициент вычисляется по формуле K = 1 - exp(-T/tau), где T - период следования входных отсчетов.

Вот то-то и оно. Знания и вера входят в конфликт.
Инженер, чтобы устранить мигание цифр на индикаторе, возьмет среднее арифметическое от 2-4 измерений. Или даже в АЦП что-нибудь из двух компонентов придумает.
Программист, ничтоже сумняшеся, будет брать экспоненту. При сем потребуется мощный процессор, плавающая запятая, дополнительные килобайты памяти, цикл решения задачи вырастет... Но он же за это не платит.
Go to the top of the page
 
+Quote Post
777777
сообщение Jan 11 2009, 11:28
Сообщение #19


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

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(Microwatt @ Jan 11 2009, 12:03) *
Инженер, чтобы устранить мигание цифр на индикаторе, возьмет среднее арифметическое от 2-4 измерений. Или даже в АЦП что-нибудь из двух компонентов придумает.
Программист, ничтоже сумняшеся, будет брать экспоненту. При сем потребуется мощный процессор, плавающая запятая, дополнительные килобайты памяти, цикл решения задачи вырастет... Но он же за это не платит.

Во-первых, вашему "инженеру" для устранения мигания цифр нужно, как я уже писал здесь, не прикрывать свое дерьмо усреднением, а устранять его, потому что если он не в состоянии получить без помех 10 разрядов, то какой он нахрен инженер - самый дешевый китайский мультиметр дает точность в два раза большую.

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

Что же касается фильтра T_ave += (T_in - T_ave) / K то для него не требуется никакой плавающей точки - он работает c целыми переменными практически в таком виде как я здесь написал. Если же вы имеете в виду экспоненту для для вычисления K, то она вычисляется один раз на калькуляторе, а если она является степенью двойки, то не требуется даже деления, можно обойтись сдвигами. А дополнительные килобайты нужны как раз при вычислении среднего арифметического - в данном случае кроме текущего и предыдущего отсчетов хранить ничего не требуется.
Go to the top of the page
 
+Quote Post
Wantcan
сообщение Jan 11 2009, 16:59
Сообщение #20


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 11-12-08
Из: Earth
Пользователь №: 42 366



Спасибо за все ответы,на этой неделе не будет времени этим заниматься,но проблему обязательно надо будет решить.Измерить и показать нужно примерный ток устройства,точность совсем не нужна,стоит в устройстве как допольнительная функция,да-помехи по питанию есть,надо будет и с ними побороться тоже,но усреднение тоже нужно.
Go to the top of the page
 
+Quote Post
rezident
сообщение Jan 11 2009, 17:04
Сообщение #21


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Demeny @ Jan 11 2009, 12:46) *
Кстати, в ней на 52 странице приведены импульсные характеристики различных типов усреднения. Сравнив графики б) и г) легко убедиться, что ИХ простого взвешенного усреднения и экспоненциального весьма схожи.
Действительно схожи. Видимо я что-то перепутал или подзабыл sad.gif
Цитата(777777 @ Jan 11 2009, 12:53) *
Смысл может и тот же, а насчет численного значения я сильно сомневаюсь. Чтобы получить фильтр с постоянной времени tau, коэффициент вычисляется по формуле K = 1 - exp(-T/tau), где T - период следования входных отсчетов.
А где это вы увидели, что я утверждал про идентичность численных значений? cranky.gif Для EMA через количество отсчетов равное N величина выходного сигнала сравняется со величиной входного единичного импульсного сигнала. Для настоящей RC-цепочки, если на вход подан единичный импульсный сигнал, то через промежуток времени равный τ=RC величина сигнала на выходе фильтра увеличиться в e раз.
Да, расчет для RC не очень простой, но существует радиолюбительские правила "пяти тау" и "двадцати тау". Первое гласит, что "за время равное τ=5*RC напряжение на конденсаторе RC-цепочки достигнет (с приемлимой точностью) 99% от входного". И соответственно для правила "двадцати тау" то же самое, но для τ=20*RC и отношение - 99,9%.
Go to the top of the page
 
+Quote Post
Tanya
сообщение Jan 12 2009, 08:02
Сообщение #22


Гуру
******

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



Цитата(rezident @ Jan 11 2009, 20:04) *
Для настоящей RC-цепочки, если на вход подан единичный импульсный сигнал, то через промежуток времени равный τ=RC величина сигнала на выходе фильтра увеличиться в e раз.

Удивительные вещи Вы пишите... Праздники не проходят бесследно?
Go to the top of the page
 
+Quote Post
777777
сообщение Jan 12 2009, 12:44
Сообщение #23


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

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(rezident @ Jan 11 2009, 20:04) *
Действительно схожи. Видимо я что-то перепутал или подзабыл sad.gif

Экспонента и прямая?.. Да, схожи, но... при наличии достаточного воображения. Или после 300...500 граммов.

Цитата(Tanya @ Jan 12 2009, 11:02) *
Цитата
Для настоящей RC-цепочки, если на вход подан единичный импульсный сигнал, то через промежуток времени равный τ=RC величина сигнала на выходе фильтра увеличиться в e раз.

Удивительные вещи Вы пишите... Праздники не проходят бесследно?

Да ладно вам придираться, все поняли о чем речь. Это если на входе единичный сигнал упал в 0, то на выходе он уменьшится в e раз через время tau=RC. На выходе этого фильтра, тоже.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 16 2009, 16:04
Сообщение #24


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(rezident @ Jan 11 2009, 20:04) *
Для настоящей RC-цепочки, если на вход подан единичный импульсный сигнал, то через промежуток времени равный τ=RC величина сигнала на выходе фильтра увеличиться в e раз.
Я предпочитаю несколько другое "качественное" понимание T=RC: касательная проведённая в момент времени 0 к экспоненте пересечёт линию установившегося значения этой экспоненты в момент времени Т=RC - это я так, к словуsmile.gif


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
Папа Карло
сообщение Jan 21 2009, 15:16
Сообщение #25


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

Группа: Новичок
Сообщений: 176
Регистрация: 15-02-08
Из: Москва
Пользователь №: 35 074



Возник вопрос по формуле T_average = T_average + (T_current - T_average) / 20.0.

Если я правильно понял, то первое значение лучше сразу занести в переменную T_average.
А если не записать, то показания будут нарастать в зависимости от кол-ва отсчётов ?
Go to the top of the page
 
+Quote Post
777777
сообщение Jan 21 2009, 16:05
Сообщение #26


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

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(Папа Карло @ Jan 21 2009, 18:16) *
Возник вопрос по формуле T_average = T_average + (T_current - T_average) / 20.0.

Если я правильно понял, то первое значение лучше сразу занести в переменную T_average.
А если не записать, то показания будут нарастать в зависимости от кол-ва отсчётов ?

Да, лучше инициализировать не нулем, а первым считанным значением, тогда фильтру не придется долго выходить на установившееся значение. А формулу лучше представить в сишном виде, даже если будешь реализовывать ее на ассемблере, легче для понимания:

T_average += (T_current - T_average) / 20.0.

То есть из считанного значения вычитаем текущее, делим на коэффициент и прибавляем к текущему. Плавающая точка здесь ни к чему, в целых числах тоже можно считать, правда там есть свои тонкости.
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jan 23 2009, 15:38
Сообщение #27


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



Хочу сказать, что для фильтрации данных с АЦП применил программный ФНЧ, любезно выложенный defunc в одной из веток AVR. Результатом остался доволен!!!


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
Wantcan
сообщение Feb 12 2009, 17:53
Сообщение #28


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 11-12-08
Из: Earth
Пользователь №: 42 366



haker_fox, прошу тнуть пальцем в то место форума,о котором вы упомянули,т.к. для меня все еще актуальна эта тема..
Go to the top of the page
 
+Quote Post
777777
сообщение Feb 13 2009, 06:15
Сообщение #29


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

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(Wantcan @ Feb 12 2009, 20:53) *
haker_fox, прошу тнуть пальцем в то место форума,о котором вы упомянули,т.к. для меня все еще актуальна эта тема..

То есть вы упорно пытаетесь усреднить помехи, вместо того, чтобы устранить их?
Go to the top of the page
 
+Quote Post
blackfin
сообщение Feb 13 2009, 06:26
Сообщение #30


Гуру
******

Группа: Свой
Сообщений: 3 106
Регистрация: 18-04-05
Пользователь №: 4 261



Цитата(777777 @ Feb 13 2009, 09:15) *
То есть вы упорно пытаетесь усреднить помехи, вместо того, чтобы устранить их?

Так ведь, "усреднить помехи" по сути и означает отфильтровать их, т.е. - устранить.. Или нет?
Go to the top of the page
 
+Quote Post
Tanya
сообщение Feb 13 2009, 07:05
Сообщение #31


Гуру
******

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



Цитата(blackfin @ Feb 13 2009, 09:26) *
Так ведь, "усреднить помехи" по сути и означает отфильтровать их, т.е. - устранить.. Или нет?

В данном случае, наверное, - нет. См 19 и 20 посты.
Go to the top of the page
 
+Quote Post
Палыч
сообщение Feb 13 2009, 07:09
Сообщение #32


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(777777 @ Jan 21 2009, 19:05) *
T_average += (T_current - T_average) / 20.0.

То есть из считанного значения вычитаем текущее, делим на коэффициент и прибавляем к текущему. Плавающая точка здесь ни к чему, в целых числах тоже можно считать, правда там есть свои тонкости.
Вот, именно - тонкости! Представьте, что разность между считанным и текущим значениями - меньше двадцати. Что получим? По этой же причине у автора вопроса и прыгают значения: в первом топике он привёл код, якобы усредняющий из двадцати значений... Имхо, сумма подсчитывается из значений измерений делённых на 5 - так усреднять, мягко говоря, не корректно.
Go to the top of the page
 
+Quote Post
777777
сообщение Feb 13 2009, 11:40
Сообщение #33


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

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(blackfin @ Feb 13 2009, 09:26) *
Так ведь, "усреднить помехи" по сути и означает отфильтровать их, т.е. - устранить.. Или нет?

Да, но только устраняют их обычно на входе АЦП, в аналоговом виде, так чтобы АЦП выдавал устойчивый код, который не пришлось бы фильтровать. И не путем подключения RC-цепочки, а путем выяснения их природы и устранения того, что их вызывает. Например, распространенная ошибка - обратный ток от светодиодных индикаторов идет по той же земле, на которой висит АЦП. Падение тока на нем вызывает скачки на земле. Эти помехи вы не устраните усреднением, потому что все они "в одну сторону", так что даже усреднив их вы получите неправильный результат.
Go to the top of the page
 
+Quote Post
blackfin
сообщение Feb 13 2009, 11:46
Сообщение #34


Гуру
******

Группа: Свой
Сообщений: 3 106
Регистрация: 18-04-05
Пользователь №: 4 261



Цитата(777777 @ Feb 13 2009, 14:40) *
Да, но только устраняют их обычно на входе АЦП, в аналоговом виде,...

Меня смутила формулировка.. ИМХО, есть разница между "устранение помех" и "устранение причин из-за которых эти помехи возникают на входе АЦП"..
Go to the top of the page
 
+Quote Post
777777
сообщение Feb 13 2009, 11:55
Сообщение #35


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

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(Палыч @ Feb 13 2009, 10:09) *
Вот, именно - тонкости! Представьте, что разность между считанным и текущим значениями - меньше двадцати. Что получим?

Получим, что результат никогда не достигнет входного значения. Но ведь и реальная, математическая экспонента никогда его не достигает! Вопрос лишь в необходимой точности. Если нужна большая - результат храним в long, а используем в качестве результата старшую половину - то есть как бы число с фиксированной точкой, в котором младшие 16 разрядов дробные.
Цитата(Палыч @ Feb 13 2009, 10:09) *
По этой же причине у автора вопроса и прыгают значения: в первом топике он привёл код, якобы усредняющий из двадцати значений... Имхо, сумма подсчитывается из значений измерений делённых на 5 - так усреднять, мягко говоря, не корректно.

Почему? Просто результат будет в 4 раза больше.

Цитата(Палыч @ Feb 13 2009, 10:09) *
По этой же причине у автора вопроса и прыгают значения: в первом топике он привёл код, якобы усредняющий из двадцати значений... Имхо, сумма подсчитывается из значений измерений делённых на 5 - так усреднять, мягко говоря, не корректно.

Пардон, не доглядел - конечно же надо сначала суммировать 20 значений, а результат делить на 5. А еще лучше - использовать степень двойки.

Сообщение отредактировал 777777 - Feb 13 2009, 12:00
Go to the top of the page
 
+Quote Post
Палыч
сообщение Feb 13 2009, 12:59
Сообщение #36


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(777777 @ Feb 13 2009, 14:55) *
Получим, что результат никогда не достигнет входного значения. Но ведь и реальная, математическая экспонента никогда его не достигает! Вопрос лишь в необходимой точности.
Математическая экспанента хотя бы стремиться к нему. В Вашем же случае мы будем иметь постоянную ошибку. Результат этого - всё тот же - отбрасывание остатка при делении, который тем больше, чем больше делитель (это - ведь, наверное, и есть те тонкости, о которых Вы говорили выше). Тогда, уж лучше что-нибудь такое:

Инициализация переменной
T_average_tmp = T_current * N
...................
T_average_tmp += (T_current - T_average)
T_average= T_average_tmp / N

Последнюю строчку, может быть, записать даже так:
T_average= (T_average_tmp + N/2) / N
Go to the top of the page
 
+Quote Post
xemul
сообщение Feb 13 2009, 14:08
Сообщение #37



*****

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



Цитата(Палыч @ Feb 13 2009, 15:59) *
...
Последнюю строчку, может быть, записать даже так:
T_average= (T_average_tmp + N/2) / N

Последнюю строчку только так и нужно писать, чтобы погрешность от целочисленного деления осталась +-0.5LSB.
Go to the top of the page
 
+Quote Post
777777
сообщение Feb 14 2009, 11:18
Сообщение #38


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

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(Палыч @ Feb 13 2009, 15:59) *
Математическая экспанента хотя бы стремиться к нему. В Вашем же случае мы будем иметь постоянную ошибку.

Что значит "постоянную ошибку"? Разумеется, экспонента будет отличаться от реальной из-за округлений, это неизбежно при цифровых вычислениях, вопрос лишь в необходимой точности. Даже если вы примените float, все равно ошибка будет, так как float тоже дискретно. Но задача ведь не в том, чтобы имитировать экспоненту, а в том, чтобы сгладить сигнал. Для этого вычисления в целых вполне достаточно.
Цитата(Палыч @ Feb 13 2009, 15:59) *
Результат этого - всё тот же - отбрасывание остатка при делении, который тем больше, чем больше делитель (это - ведь, наверное, и есть те тонкости, о которых Вы говорили выше). Тогда, уж лучше что-нибудь такое:
Инициализация переменной
T_average_tmp = T_current * N
...................
T_average_tmp += (T_current - T_average)
T_average= T_average_tmp / N

Тогда уж лучше что-нибудь такое:
Код
    static long Adc0, AdcF;

    Adc0 = (long)ADC << 16;
    AdcF += (Adc0 - AdcF)>>3; // или разделить на нужное число, если оно не степень двойки
    int Result = AdcF >> 16;

Правда, gnu-тый компилятор не очень эффективно кодирует сдвиги (не знаю, может IAR поумнее), поэтому этот участок лучше написать на ассемблере.
Смысл в том, что в старших 16 битах AdcF хранится фильтрованное значение, а в младших - его дробная часть, т.е. оно представляет собой число с фиксированной точкой. При кодировании на ассемблере можно даже подойти к делению (сдвигу) более творчески: если в отбрасываемых битах старший 1, то к оставшимся прибавляем 1, а если 0 - то не прибавляем, т.е. выполняем деление с округлением до целого. Тогда не будет ошибки с отбрасыванием, которой ты так боишься.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Feb 14 2009, 15:07
Сообщение #39


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

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



Цитата(777777 @ Feb 14 2009, 13:18) *
Тогда уж лучше что-нибудь такое:
Код
    static long Adc0, AdcF;

    Adc0 = (long)ADC << 16;
    AdcF += (Adc0 - AdcF)>>3; // или разделить на нужное число, если оно не степень двойки
    int Result = AdcF >> 16;

...
Смысл в том, что в старших 16 битах AdcF хранится фильтрованное значение, а в младших - его дробная часть, т.е. оно представляет собой число с фиксированной точкой.
+1
Давно делаю похожим образом, часто запас разрядов в аккумуляторе делаю равным числу сдвигов для деления на коффициент фильтра (он степень двойки). Т.е. для беззнаковых 10-битных отсчётов и "рециркуляции" 7/8, т.е. весе очередного отсчёта 1/8 будет так:
Код
    uint16_t acc;
void update(uint16_t val) {
   acc = acc - ((acc + 4) >> 3) + val;
}

uint16_t get_result() {
   return  (acc + 4) >> 3;
}

Собственно, с не-степенью двойки будет аналогично, просто
Код
(acc+4)>>3
езде заменится на
Код
(acc+DIVIDER/2)/DIVIDER
, но я не вижу в этом особого смысла. Если задача так чувствительна к тому, что новый отсчёт будет входить не с 1/8 или 1/16, а имено с 1/10 или 1/13, то скорее всего там и фильтр нужен более высокого порядка.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Wantcan
сообщение Mar 2 2009, 16:57
Сообщение #40


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 11-12-08
Из: Earth
Пользователь №: 42 366



Пожалуйста,помогите переделать найденный на этом форуме программный ФНЧ под мои условия,сам не могу разобраться.
Код
int nStepFilter( int val)
{
#define  shift  (4)   // n = 2^shift
#define  lsb    ((1 << (shift)) >> 1)

    static int x = 0;
    int av = (x + lsb) >> shift;

    x += val - av;

    return av;
#undef lsb
#undef shift
}
Go to the top of the page
 
+Quote Post
Wantcan
сообщение Mar 16 2009, 11:10
Сообщение #41


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 11-12-08
Из: Earth
Пользователь №: 42 366



Остановился на таком варианте
Код
ta++; if(ta==20){ta=0;temp=tempADC/100;}
   if(ta==0)tempADC=0;  
   tempADC+=read_adc(0);
Go to the top of the page
 
+Quote Post
Флюктуация вакку...
сообщение Aug 15 2015, 12:22
Сообщение #42


Местный
***

Группа: Участник
Сообщений: 346
Регистрация: 15-12-13
Из: Планета Земля
Пользователь №: 79 630



Нужно создать в оперативной памяти закольцованный FIFO-буфер с двумя указателями (PTR_first и PTR_last).

И регистр суммы. Разрядность его должна быть достаточной для хранения суммы 20-ти значний без округления.

Как только приходит очередное значение от АЦП Вы его записываете в ячейку, на которую указывает PTR_last, добавляете его к сумме и вычитаете из суммы значение, на которое указывает PTR_first.

После чего двигаете PTR_first и PTR_last на следующие ячейки в кольце.

Таким образом у Вас всегда в регистре cуммы будет акутульное значение среднего, умноженное на 20.

Чтобы получить среднее достаточно будет поделить значение, находящееся в данный момент в регистре суммы на 20.

Сообщение отредактировал Флюктуация ваккума - Aug 15 2015, 12:23
Go to the top of the page
 
+Quote Post
Bronislav
сообщение Sep 4 2015, 06:15
Сообщение #43


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

Группа: Участник
Сообщений: 118
Регистрация: 23-01-06
Пользователь №: 13 477



Такой вариант не подойдет?
for(i=0;i<20;i++) // усредняем 20 выборки
{
ADC_cur = ADС;
if (i == 0)
{
ADC_old = ADC_cur; // первое значение отправляем в сумму
ADC_sum = ADC_old;
}
else
{
ADC_old += ADC_cur; // сложили текущее значение со старым
ADC_old /= 2; // поделили на 2
ADCsum += ADC_old; // просуммировали
}
}
ADC_cur = ADC_sum/20; // cумму поделили на 20 */
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 Текстовая версия Сейчас: 1st August 2025 - 19:59
Рейтинг@Mail.ru


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