Усреднение значений с аналогового входа
- Войдите на сайт для отправки комментариев
Сб, 25/02/2017 - 00:39
Есть идея усреднения значений, не могу понять как сделать: берем массив например из 5 ячеек, в каждую ячейку массива пишем значения с аналоговго входа при каждом проходе цикла loop и далее делим сумму всех ячеек на количество ячеек, таким образом получаем как бы среднее арифметическое.
И идея в том, что при заполнении всех 5 ячеек массива, следующее новое значение добалять к примеру в первую ячейку а все остальные значения сдвигать на ячеку ниже.
А так же может кто подскажет хорошие способы для усреднения, заранее благодарен ;)
Самое лучшее усреднение это конденсатор на аналоговом входе.
Руки чешутся, приехали АЦП I2C ADS1115 а значения скакают...
А зачем их сдвигать? Ведь сумма не зависит от перестановки слагаемых.
Делайте обычное среднее арифметическое, на первое время хватит и такой точности.
Ищите по форуму, уже скулы свело повторять одно и тоже. Конденсатор годится чтоб в глаз советчику засунуть.
ПС. ADS1115 честная, сам проверял, если на входе постоянка, то ничё не скачет, стоит как влитое. В отличии от ардуиновского АЦП кстати. Если скачит - шум на входе.
Как зачем? мы записываем новые показания в первую ячейку сдвигая все старые показания на ячейку ниже, а соответственно из последней удаляются самые старые показания.
Все верно, шум есть так как щупаю наряжение с недоделанного лабараторного БП.
Не нужно ничего сдвигать. Просто использовать последние n измерений. А их сумма от перестановки не изменится, только лишнее действие и время процессора.
http://arduino.ru/forum/programmirovanie/usrednenie-znachenii-s-potentsi...
код работает странно:
коэффициент сглаживания = 2 показывает 3.1735V
коэффициент сглаживания = 3 показывает 3.1151V
коэффициент сглаживания = 4 показывает 3.0852V
коэффициент сглаживания = 5 показывает 3.0689V
и это при неизменном напряжении на входе!
Там надо внести исправления (переделать все на float и поменять местами две строчки), ниже расписано, а ту запись нет возможности исправить.
И учтите, что первые n измерений будут по нарастающей.
В самой ардуино ИДЕ есть пример
/* Smoothing Reads repeatedly from an analog input, calculating a running average and printing it to the computer. Keeps ten readings in an array and continually averages them. The circuit: * Analog sensor (potentiometer will do) attached to analog input 0 Created 22 April 2007 By David A. Mellis <dam@mellis.org> modified 9 Apr 2012 by Tom Igoe http://www.arduino.cc/en/Tutorial/Smoothing This example code is in the public domain. */ // Define the number of samples to keep track of. The higher the number, // the more the readings will be smoothed, but the slower the output will // respond to the input. Using a constant rather than a normal variable lets // use this value to determine the size of the readings array. const int numReadings = 10; int readings[numReadings]; // the readings from the analog input int readIndex = 0; // the index of the current reading int total = 0; // the running total int average = 0; // the average int inputPin = A0; void setup() { // initialize serial communication with computer: Serial.begin(9600); // initialize all the readings to 0: for (int thisReading = 0; thisReading < numReadings; thisReading++) { readings[thisReading] = 0; } } void loop() { // subtract the last reading: total = total - readings[readIndex]; // read from the sensor: readings[readIndex] = analogRead(inputPin); // add the reading to the total: total = total + readings[readIndex]; // advance to the next position in the array: readIndex = readIndex + 1; // if we're at the end of the array... if (readIndex >= numReadings) { // ...wrap around to the beginning: readIndex = 0; } // calculate the average: average = total / numReadings; // send it to the computer as ASCII digits Serial.println(average); delay(1); // delay in between reads for stability }Собственно, работа с массивом делается так.
Допустим, мы хотим делать усреднение по N ячейкам.
1. Определяем массив на N ячеек.
2. Делаем первое измерение (из setup()), его результат заносим во все ячейки сразу (циклом).
3. Заводим целочисленную переменную (byte K) - номер ячейки в которую будеим писать. Инициализируем этоу переменную любым числом от 0 до N-1. Это все в setup().
4. Теперь в loop() читаем новое значение и записываем его в ячейку массива с номером K.
5. Инкрементируем переменную K, находим остаток по модулю N.
6. Считаем среднее по массиву (любым алгоритмом: арифметическое, геометрическое, медиана...) и используем его по назначению, например, выводим на экран.
В принципе, в случае среднего арифметического в п.6. можно существенно сократить объем вычислений. Для этого вместо 4-6 делаем:
4. Заводим статическую переменную S достаточно разрядности для хранения суммы.
5. После п.2 считаем сумму и заносим ее в переменную S. (в setup())
6. В loop() вычитаем из S значение K-й ячейки массива.
7. Читаем новое значение, заносим его в К-ю ячейку, а также прибавляем к сумме.
8. Инкрементируем К, находим остаток по модулю N.
Таким бразом мы изюавляемся от необходимости суммирования массива на каждом шаге.
Ох...не получилось
Как зачем? мы записываем новые показания в первую ячейку сдвигая все старые показания на ячейку ниже, а соответственно из последней удаляются самые старые показания.
Все верно, шум есть так как щупаю наряжение с недоделанного лабараторного БП.
Что-то логик не предложил цифровой фильтр, а ведь работает:
void inmax471() { for (int j=1; j <= 16; j++) { Data_max471=analogRead(Pin_max471); G+=Data_max471-(G>>8); Data_max471=G>>8; } } // END INPUT FILTERВ счётчике гейгера для замерянной последовательности из десяти значений среднее получилось - 0.24461, а вот вычисление среднего на каждой итерации (среднее со средним) на этом же блоке значений дало - 0.263529
Этот метод работает только на float. На целочисленной математике никогда не приблизится к истинному значению на величину глубины сглаживания.
так все же, как получить среднее арефметическое float из 3-5 итераций самым простоым способом?
*пробовал с массивом по идеи из первого поста, но сильно начинает тупить
Самое простое - сложить и поделить на 3-5.
А если нужно не получить, а получать, то каждый последующий результат помещать в очередную ячейку, ничего не сдвигая.
Старый, это уже совсем другой фильтр.
int a[5]; byte i=0; int value; void setup() { } void loop() { i++; if (i>=5) i=0; a[i]=analogRead(A0); value =(a[0]+a[1]+a[2]+a[3]+a[4])/5; }Что-то логик не предложил цифровой фильтр, а ведь работает:
void inmax471() { for (int j=1; j <= 16; j++) { Data_max471=analogRead(Pin_max471); G+=Data_max471-(G>>8); Data_max471=G>>8; } } // END INPUT FILTERЧегож "не прндложил"?! Еще в 4-м сообщении написал мол ищите. Сколько ж можна мне его разжевывать?!
Никак нет. Хотя причина вашего сомнения понятна. Действительно приходится работать с дробной частью. И она там, как суслик, она есть ))) Переменная G в цитированом коде не случайно берется большей розрядности, например long. В ней значение хранится в форме с фиксированой запятой, старшие 24 разряда целая часть, а младшие 8 - дробная. Это четко видно в последней строке кода, где эта самая дробная часть отбрасывется. А строкой выше мы в G засовываем входное значение, по математической формуле оно должно быб быть Data_max471/256, но т.к. формат G отакой хитрый то деление (или сдвиг) становится не нужным.
Таким образом G как бы немножко float.
ПС. Везде выше цифра 8 и 2 в этой степени, т.е. 256 - не догма, можна написать к примеру 5 и 32, если нужно. Но 8 особо хороша еще и тем, что >>8 очень просто делается прцессором.
Старый, это уже совсем другой фильтр.
На самом деле почти тоже самое, только коэффициент другой. В Value = (Value*2+analogRead(A0))/3; К=1/3 и дробную часть игнорим, а в том, что выше был к=1/256 и дробную учитываем. Разумеется из-за различия коэффициентов степень сглаживания тоже различается, но подход тот же.
Вот так смотрю и я пойму как это работает )))
Да, цифровой выглаживает как хорошие мужские руки выглаживают барышень )))
Шероховатостей почти нет, разброс +- единичка от текущего значения
А что получим на первой итерации при value = 0???
Не годится видимо (0*2+ 1)/3 - треть от значения
Значит первое чтение value перенести в setup
Спасибо все откликнувшимся, получилось пока что так:
#include <Wire.h> #include <LiquidCrystal_I2C.h> #include <Adafruit_ADS1015.h> Adafruit_ADS1115 ADS(0x48); // адрес АЦП LiquidCrystal_I2C lcd(0x3F, 16, 2); // адрес lcd 1602 float Voltage = 0.0; long ads_tmp = 0; void setup(){ lcd.init(); // Инициализация дисплея lcd.backlight(); // Включаем подсветку дисплея // Включаем внутренний опорник АЦП ADS1115 на 4.096V ADS.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV ADS.begin(); //включаем АЦП } void loop(){ int16_t ADS_a0; // на выходе преобразования АЦП мы получаем 16-разрядное знаковое целое ADS_a0 = ADS.readADC_SingleEnded(0); // измеряем напряжение if (ADS_a0+5 <= ads_tmp || ADS_a0-5 >= ads_tmp) { ads_tmp = (ads_tmp+ADS_a0)/2; Voltage = ads_tmp * (4.096 / 32767.5); // пересчитываем в привычные вольты } lcd.setCursor(0, 0); lcd.print(ADS_a0, 7); lcd.print(" "); lcd.print(ads_tmp, 7); lcd.print(" "); lcd.setCursor(0, 1); lcd.print("U="); lcd.print(Voltage, 4); lcd.print("V "); delay(50); }Глянуть бы ассемблерный код этой конструкции:
if (ADS_a0+5 <= ads_tmp || ADS_a0-5 >= ads_tmp) {Это я к чему? Не зная аsm atmega, а для привычного intel8080 результат от сложения или вычитания переменной с константой будет храниться в ячейке этой переменной, кто выделяет ячейку для хранения временного результата, компилятор? Уже в этой конструкции таких ячеек надо две
Весь смысл этой конструкции в данном случае, сделать простое вычесление в IF если значения попадают в +-5 едениц, иначе уже делаем чуть сложнее вычисление + предварительное вычисление в IF, а так же получается небольшая как по мне "стабилизация" выходных данных.
я б заменил на это:
Или это (смотря что нужно в функционале):
Суть та же, но нагляднее.
Весь смысл этой конструкции в данном случае, сделать простое вычесление в IF если значения попадают в +-5 едениц, иначе уже делаем чуть сложнее вычисление + предварительное вычисление в IF, а так же получается небольшая как по мне "стабилизация" выходных данных.
Логика мне понятна, мне непонятна физическая сущность, где хранятся промежуточные результаты вычислений )))
в ads_tmp и если попадаем в IF то перезаписываем ads_tmp и Voltage
На самом деле почти тоже самое, только коэффициент другой.
Ну т.е. КИХ и БИХ отличаются только коэффициентом?
PS. И еще: fixed ни разу не float. Даже немножко.
Не зная аsm atmega, а для привычного intel8080 результат от сложения или вычитания переменной с константой будет храниться в ячейке этой переменной, кто выделяет ячейку для хранения временного результата, компилятор? Уже в этой конструкции таких ячеек надо две
Не зная аsm atmega, а для привычного intel8080 результат от сложения или вычитания переменной с константой будет храниться в ячейке этой переменной, кто выделяет ячейку для хранения временного результата, компилятор? Уже в этой конструкции таких ячеек надо две
я выделял память в основном блоке, ну или стеком пользовался
На самом деле почти тоже самое, только коэффициент другой.
Ну т.е. КИХ и БИХ отличаются только коэффициентом?
PS. И еще: fixed ни разу не float. Даже немножко.
И кто там из них КИХ? У КИХ в правой части не может быть функции от выходного сигнала, потому КИХ - это то что с массивами было..
Вот именно средее арифметическое по массиву - это и есть КИХ.
PS. И еще: fixed ни разу не float. Даже немножко.
Отнюдь.
Целые - частный случай fixed point, у них нет ни мантиссы, ни порядка. В отличие от float, у которых все это есть + дополнительные свойства типа единичного старшего бита и пр. Ну и способы обработки на ЭВМ у всех fixed point (включая integer) одни, а у всех float point - другие.
Т.е. fixed point - это одно, а float - совсем другое.
Да, кстати, как у fixed, так и у float дробной части может не быть, так что в качестве отличительного признака не годится.
... на 1115 с фильтром http://arduino.ru/forum/proekty/ochen-tochnyi-voltmetr-na-arduino посты 13, 28 .
Может опытные скажут "костыли", мне же нравится как работает.
И кто там из них КИХ? У КИХ в правой части не может быть функции от выходного сигнала, потому КИХ - это то что с массивами было..
Вот именно средее арифметическое по массиву - это и есть КИХ.
Вы читаете только первое предложение из постов? Спецом цитирую два предложения.
//На самом деле почти тоже самое, только коэффициент другой. В Value = (Value*2+analogRead(A0))/3; К=1/3 и дробную часть игнорим, а в том, что выше был к=1/256 и дробную учитываем.
Четко видно к чему относится "почти тоже самое". Убогость на массивах не рассматривается вобще.
PS. И еще: fixed ни разу не float. Даже немножко.
[/quote]
Отнюдь.
Целые - частный случай fixed point, у них нет ни мантиссы, ни порядка. В отличие от float, у которых все это есть + дополнительные свойства типа единичного старшего бита и пр. Ну и способы обработки на ЭВМ у всех fixed point (включая integer) одни, а у всех float point - другие.
Т.е. fixed point - это одно, а float - совсем другое.
Да, кстати, как у fixed, так и у float дробной части может не быть, так что в качестве отличительного признака не годится.
[/quote]
Может быть, может не быть, дополнительніе свойства и способ представления- софизм, пи..еж и провокация.
Есть конкретные возражения по обединяющему факту , что fixed и float представляет числа с дробной частю и имея необходимость вести расчет в таковых числах возможно применение именно этих форматов а не других?
ПС. про double в курсе, про разные виды fixed и float информирован, потому кончай флудить не по теме, мы и так изумлены инфой про мантисы и порядок, с 6-го класса школы не слышали ;) Сразу пиши этюд про float.