Усреднение значений с потенциометра

Pyotr
Offline
Зарегистрирован: 12.03.2014

nik182 пишет:
В целочисленной арифметике нет округления. Только обрезания. Округления в дробной. Если использовали дробную, то нет разницы. Без округления и так всё придёт к правильному значению. В целочисленной надо использовать стандартную формулу, а не её приближение.

Округление происходит. Не результата вычисления, а в результате-в процессе  вычисления.

int a, b, c;

c = a / b;//дробная часть отбрасывается

c = (a + b/2) / b;//сначало прибавляем 0.5, а затем отбрасываем дробную часть 
 Только делаем это с целыми числами. Видно, если раскроем скобки.
(a + b/2) / b => (a/b + 0.5) 
 

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013
mastersan-mh
Offline
Зарегистрирован: 10.10.2018

Некропост, и всё-же.

Надеюсь, этот пост убережёт новых исследователей arduino от старых ошибок.

Для начала предложу класс, занимающийся усреднения значений.

class Average3
{
public:
    Average3(unsigned int factor);
    virtual ~Average3();
    virtual void factorSet(unsigned int factor);
    virtual void appendValue(int value);
    virtual int averageGet();
private:
    unsigned int factor;
    unsigned int len;
    int mean;
    unsigned int value_weight;
    int value_prev;
};


Average3::Average3(unsigned int factor)
{
    this->factor = factor;
    this->len = 0;
    this->mean = 0;
    value_weight = 0;
    value_prev = 0;
}

Average3::~Average3()
{
}

void Average3::factorSet(unsigned int factor)
{
    this->factor = factor;
    this->len = factor;
}

void Average3::appendValue(int value)
{
    if (factor == 0)
    {
        mean = value;
        len = 0;
        return;
    }

    if(value_prev == value)
    {
        ++value_weight;
    }
    else
    {
        value_weight = 1;
        value_prev = value;
    }

    if(len < factor)
    {
        ++len;
    }

    mean = (mean * (len - value_weight) + value * value_weight) / len;

}

int Average3::averageGet()
{
    return mean;
}

Плюсы:

1. Не требуется хранить массив значений, по которым ведётся усреднение

2. Усреднённое значение, за счёт использования веса последнего посупившего значения, будет ближе к значению, как если бы вычисление было выполнено по классической схеме, а в итоге и достигнет его.

Минусы:

1. Скорость схождения немного ниже, чем для классической схемы.

 

Таблица с замерами, время между замерами 100 мс, фактор усреднения 5:

A B C D E F
фактическое классическое Average3 B-A C-A C-B
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
969 1009 1012 40 43 3
823 959 974 136 151 15
638 863 906 225 268 43
476 726 820 250 344 94
328 566 721 238 393 155
195 409 615 214 420 206
66 266 505 200 439 239
0 147 404 147 404 257
0 65 242 65 242 177
0 16 96 16 96 80
0 0 19 0 19 19
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
57 14 11 -43 -46 -3
139 49 36 -90 -103 -13
217 103 72 -114 -145 -31
307 180 119 -127 -188 -61
423 271 179 -152 -244 -92
544 372 252 -172 -292 -120
645 479 330 -166 -315 -149
726 584 409 -142 -317 -175
799 678 487 -121 -312 -191
871 760 563 -111 -308 -197
963 839 643 -124 -320 -196
1023 914 719 -109 -304 -195
1023 970 840 -53 -183 -130
1023 1008 949 -15 -74 -59
1023 1023 1008 0 -15 -15
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1011 1020 1020 9 9 0
935 998 1003 63 68 5
868 959 976 91 108 17
803 904 941 101 138 37
730 834 898 104 168 64
656 764 849 108 193 85
590 694 797 104 207 103
520 624 741 104 221 117
431 549 679 118 248 130
340 470 611 130 271 141
244 383 537 139 293 154
150 291 459 141 309 168
72 201 381 129 309 180
0 116 304 116 304 188
0 55 182 55 182 127
0 18 72 18 72 54
0 0 14 0 14 14
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
21 5 4 -16 -17 -1
116 34 26 -82 -90 -8
213 87 63 -126 -150 -24
334 171 117 -163 -217 -54
464 281 186 -183 -278 -95
569 395 262 -174 -307 -133
642 502 338 -140 -304 -164
711 596 412 -115 -299 -184
792 678 488 -114 -304 -190
859 751 562 -108 -297 -189
933 823 636 -110 -297 -187
999 895 708 -104 -291 -187
1023 953 771 -70 -252 -182
1023 994 871 -29 -152 -123
1023 1017 962 -6 -61 -55
1023 1023 1010 0 -13 -13
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0
1023 1023 1023 0 0 0

Начнём по порядку:

1. К алгоритму от Tomasina:

Здесь не рассматривается граничное условие, когда мы не накопили averageFactor значений. Именно поэтому требовался пресловутый "разогрев датчика". Эх, математика...

2.

Правильно было сказано:

nik182 пишет:

В целочисленной арифметике выражение 

 sensorValue = (sensorValue * (averageFactor - 1) + NewSensorValue) / averageFactor; 

никогда не приблизится вверх к  NewSensorValue на величину averageFactor  .

Поэтому данное усреднение работает толко на float. Если в проекте не используются float, то об этом следует помнить.

Не нужно забывать, что мы работаем с целыми значениями. Именно поэтому я и использовал "вес".

3.

leshak пишет:

Минус его решения только один: чуть чуть сложнее для понимания "как оно работает".

Господа, если вам сложно понимать математические формулы - тогды Вы, наверное, не ту профессию выбрали.

 

a5021
Offline
Зарегистрирован: 07.07.2013

mastersan-mh пишет:
Для начала предложу класс, занимающийся усреднения значений.

А че только ванильный класс? Почему без замыканий, лямбд и каррирования?

Цитата:
Господа, если вам сложно понимать математические формулы - тогды Вы, наверное, не ту профессию выбрали.

Но вы то точно ту? Не хотите объясниться, какая нелегкая подорвала вас простые вещи излагать тут сложным образом?

Ну и цитатка на закуску: "Вопреки стереотипам, в программировании наиболее важны не математические способности, а лингвистические. Об этом еще в 1982 году в своих «Этюдах для программистов» писал Чарльз Уэзрел. Он обратил внимание на вербальные способности как на важный аспект личности успешного программиста, имея в виду умение работать с грамматикой как искусственных, так и естественных языков."

Vittorio
Offline
Зарегистрирован: 02.02.2015

Дайте хоть пример вызова этого класса.
Я понимаю, что для вас это настолько просто, что само собой разумеется ;)

sadman41
Offline
Зарегистрирован: 19.10.2016

Есть три байта: R G и B. Возможно ли из них вывести цветовую температуру в Кельвинах? 

От решения ни жизнь, ни доход не зависит, просто не могу осознать... Незамысловатый математическо-логический перевод Кельвин->RGB есть, а вот обратного никак не могу найти. Только таблицы километровые. Я так понимаю, что не все так однозначно, цветовые пространства надо учитывать, длины волн и т.д.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

sadman41 пишет:

Есть три байта: R G и B. Возможно ли из них вывести цветовую температуру в Кельвинах? 

От решения ни жизнь, ни доход не зависит, просто не могу осознать... Незамысловатый математическо-логический перевод Кельвин->RGB есть, а вот обратного никак не могу найти. Только таблицы километровые. Я так понимаю, что не все так однозначно, цветовые пространства надо учитывать, длины волн и т.д.

1. Математический путь.

1.1. Аналитически. берешь три функции для R,G,B от лямбда. и Функцию излучения АЧТ от лямбда и t. В видимом диапазоне решаешь задачу максимального приближения по среднему квадрату.

1.2. Тоже, только на компе с таблично заданными, если нет аналитического выражения.

2. Простой путь. В нужном диапазоне, а как я понимаю, это для фото применения? просто апроксимируем табличные значения подходяшим многочленом. Решение ищем на компе. Выбираем несколько видов многочленов, по наименьшим квадратам подбираем лучший.

==================

ну и да, в общем случае нет решения. Так как не любая комбинация RGB отвечает какому-то излучению АЧТ.

sadman41
Offline
Зарегистрирован: 19.10.2016

wdrakula пишет:

ну и да, в общем случае нет решения. Так как не любая комбинация RGB отвечает какому-то излучению АЧТ.

Почему-то я там и подумал, что тут байтовыми сдвигами не обойдешься ))

Задача не для фото. Просто есть датчик ADPS-9960, который я решил к мониторингу прикрутить. Обычный ambient в люксах получаю, всё ок. Но он еще измеряет освещенность через три светофильтра. В даташите написано, что из сил трех цветов можно вывести Кельвины, однако формулы не дано. Я поискал, потом подумал, что гуглом пользоваться не умею. Еще подумал. Решил спросить - может искать и нечего. А так было бы интересно, конечно, определять - натуральный свет сейчас в помещении или уже искусственный.

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:

Есть три байта: R G и B. Возможно ли из них вывести цветовую температуру в Кельвинах? 

 

Наглядный график. Из него видно, что очень немногие комбинации RGB соответсвуют какой-либо температуре.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

sadman41 пишет:

Есть три байта: R G и B. Возможно ли из них вывести цветовую температуру в Кельвинах? 

От решения ни жизнь, ни доход не зависит, просто не могу осознать... Незамысловатый математическо-логический перевод Кельвин->RGB есть, а вот обратного никак не могу найти. Только таблицы километровые. Я так понимаю, что не все так однозначно, цветовые пространства надо учитывать, длины волн и т.д.

Не переживай, задача в общем случае неразрешима.

Это как, зная уравнение прямой, не составит труда найти 3 лежащих на ней точки.

А вот провести прямую через 3 произвольные точки - тут поседеешь.

Старый
Offline
Зарегистрирован: 09.10.2016

Не знаю, мужики . Все туту умные такие . В школе и я неплохо знал мати... мате..., арихметику. Но с годами как-то все прошло- я знаю что знаю про это. А вот как называется "ЭТО" стал забывать.

Нашел одну фигушку тута и использовал.

Но как по мне- без всяких фильтров все работает тоже не плохо. 

А тут , в теме-последних 30-40 постов- меряются вялыми писюнами молодые дрочеры со старперами.Развели холивар, гавнюки. ПятницаЖ уже прошла, нехристи!

Pyotr
Offline
Зарегистрирован: 12.03.2014

nik182 пишет:

В целочисленной арифметике выражение 

 sensorValue = (sensorValue * (averageFactor - 1) + NewSensorValue) / averageFactor; 

никогда не приблизится вверх к  NewSensorValue на величину averageFactor  .

Поэтому данное усреднение работает толко на float. Если в проекте не используются float, то об этом следует помнить.

 

Просто процитировал справедливое утверждение. 
Попытался немного изменить выражение.

// было:  sensorValue = (sensorValue * (averageFactor - 1) + NewSensorValue) / averageFactor; 
int delta = NewSensorValue - sensorValue;
sensorValue = (sensorValue * (averageFactor - 1) + sensorValue + NewSensorValue - sensorValue) / averageFactor = 
= (sensorValue * averageFactor + NewSensorValue - sensorValue) / averageFactor = 
= (sensorValue * averageFactor + delta) / averageFactor = 
= sensorValue + delta / averageFactor; 
//стало:  sensorValue += delta / averageFactor; 

И пример усреднения четырех значений (правильней величина усреднения или еще как-то) с потенциометра 33 кОм подключен на А0. При дотрагивании пальцем до А0 среднее скачет +- 3 единицы, а значения АЦП +- 10-15 единиц.

word  prevMillis, intervalMs = 70;//кратно 10 и не кратно 20
int valAdc, avgAdc;

void setup() { 
  Serial.begin(9600);
}
void loop() {
  static byte counter = 0;  
  static int8_t arrDelta[4] = {0}; 
  static int arrAdc[4] = {0}; //для печати
  
  if((word)millis() - prevMillis >= intervalMs){
    prevMillis += intervalMs;    
    int delta = 0;    
    arrAdc[counter] = analogRead(A0);
    delta = arrAdc[counter] - avgAdc;   
    arrDelta[counter] = delta % 4;//накапливаем погрешность
    
    //вместо вычисления:  avgAdc = (3*avgAdc + arrAdc[counter]) / 4;
    //= (4*avgAdc + (arrAdc[counter] - avgAdc)) / 4 =
    // = avgAdc + (arrAdc[counter] - avgAdc) / 4 = avgAdc + delta /4;
    //применим:  avgAdc += delta /4;
    
    if(delta){
      int sum = arrDelta[0] + arrDelta[1] + arrDelta[2] + arrDelta[3];
      avgAdc += (delta + sum) /4;
    }
    if(++counter > 3){
      counter = 0;
      for(byte i=0; i<4; i++){
        Serial.println(arrAdc[i]);//посмотреть усредняемые значения
      } 
      Serial.println(avgAdc);
      Serial.println();      
    }
  }    
}

 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Я в таких случаях не заморачиваюсь

uint16_t getAnalogValue(const uint8_t AAnalogPin) {
   uint16_t result = 0;
   for (uint8_t i=0; i<16; i++) result+=analogRead(AAnalogPin);
   return (result >> 4);
}

 

Pyotr
Offline
Зарегистрирован: 12.03.2014

Деда, какой там будет результат, если прилетят 15 значений по 333 и одно 332 ;))
Я, если так делаю, то результат не делю на 16, а использую как есть.

if(result > setVal * 16) {
 что-то делаю
}

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Pyotr пишет:

Деда, какой там будет результат, если прилетят 15 значений по 333 и одно 332 ;))
Я, если так делаю, то результат не делю на 16, а использую как есть.

if(result > setVal * 16) {
 что-то делаю
}

так тема была - усреднять

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Pyotr пишет:

Деда, какой там будет результат, если прилетят 15 значений по 333 и одно 332 ;))

332

Pyotr
Offline
Зарегистрирован: 12.03.2014

ua6em пишет:

так тема была - усреднять

да, но усреднять не ради усреднения. Что-то мы потом будем же с этим результатом делать.
У меня вот потенциометр проволочный многооборотный в качестве датчика положения. Он сам шумит, привод вибрацию дает. Нужно знать мгновенную скорость хотяб каждые 50 мс, чтоб корректировать ШИМ и останавливать привод в нужном положении.

Оно все хоть и работает у меня сейчас, но хочется как-то проще, красивше... 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

DetSimen пишет:

Я в таких случаях не заморачиваюсь

uint16_t getAnalogValue(const uint8_t AAnalogPin) {
   uint16_t result = 0;
   for (uint8_t i=0; i<16; i++) result+=analogRead(AAnalogPin);
   return (result >> 4);
}

return ((result + 8) >> 4);

 

Morroc
Offline
Зарегистрирован: 24.10.2016

Pyotr пишет:

Оно все хоть и работает у меня сейчас, но хочется как-то проще, красивше... 

Вряд ли что то можно сделать с 333/332. Вот если бы были явные выбросы (все 333, а один 323) - можно было бы выкинуть сильно отличающиеся от среднего и посчитать без них.

Pyotr пишет:

При дотрагивании пальцем до А0 среднее скачет +- 3 единицы, а значения АЦП +- 10-15 единиц.

Поставьте вместо 33к где то 3к и потрогайте его пальцем )

Pyotr
Offline
Зарегистрирован: 12.03.2014

Tomasina пишет:

https://habrahabr.ru/post/325590/

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

Код

#define N (4)
int filter(int x)
  {
  static int n;
  static int m[N];
  static int y;
  y=y+(x-m[n]);
  m[n]=x;
  n=(n+1)%N;
  return y/N;
  }

 

Morroc
Offline
Зарегистрирован: 24.10.2016

Аппаратно не пробовали решить это ?

Pyotr
Offline
Зарегистрирован: 12.03.2014

Morroc пишет:

Вряд ли что то можно сделать с 333/332. Вот если бы были явные выбросы (все 333, а один 323) - можно было бы выкинуть сильно отличающиеся от среднего и посчитать без них.

Я делаю обрезание )) значений АЦП. Этакий программный стабилитрон что ли. Тоесть, при чтении АЦП каждые 50 мс, значение в моем случае не может отличаться более чем на 5 единиц при макс. скорости движения привода. Те попугаи что выходят за рамки +-5 единиц обрезаю.

Morroc пишет:

Pyotr пишет:

При дотрагивании пальцем до А0 среднее скачет +- 3 единицы, а значения АЦП +- 10-15 единиц.

Поставьте вместо 33к где то 3к и потрогайте его пальцем )

Сопротивление потенциометров конечно меньше - 1-2 кОм. Но работает это на улице рядом с ДПТ и длина кабеля (в экране) несколько метров. Поэтому там помех тоже хватает.

 

Morroc
Offline
Зарегистрирован: 24.10.2016

Кабель от потенциометра до АЦП несколько метров ?

Pyotr
Offline
Зарегистрирован: 12.03.2014

Morroc пишет:

Кабель от потенциометра до АЦП несколько метров ?

В одной теплице (самая первая поделка) 7 м телефонный четырехжильный (от удлинителя телефонного). На нем два потенциометра, питание и земля. Пять лет работает. Защиты от статики нет!!  AVR неубиваемы!!! Потенциметры проволочные советские забыл тип, коричневые такие, не герметичные. В ливень как-то смотрю в теплице по ним вода бежит, и дальше по кабелю на почву. Хорошо что не в контроллер)))