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

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 неубиваемы!!! Потенциметры проволочные советские забыл тип, коричневые такие, не герметичные. В ливень как-то смотрю в теплице по ним вода бежит, и дальше по кабелю на почву. Хорошо что не в контроллер)))

sokhib
Offline
Зарегистрирован: 29.08.2016
int val = 0;
int temp[11];
int i = 0;
int sum;
float average;
void setup() 
{
 Serial.begin(9600); 
}

void loop() {
     
for ( i=9; i>=1; i--)
{
  temp[i+1]= temp[i]; 
}
temp[1]= analogRead(A5); 
sum=0;  
for ( i=1; i<=10; i++)
{
  sum= sum + temp[i]; 
}
average= (float)sum/10.0;
 
  }
}

 

 

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

sokhib пишет:

int val = 0;
int temp[11];
int i = 0;
int sum;
float average;
void setup() 
{
 Serial.begin(9600); 
}

void loop() {
     
for ( i=9; i>=1; i--)
{
  temp[i+1]= temp[i]; 
}
temp[1]= analogRead(A5); 
sum=0;  
for ( i=1; i<=10; i++)
{
  sum= sum + temp[i]; 
}
average= (float)sum/10.0;
 
  }
}

 

 

 

Этта шо?  О_О

sokhib
Offline
Зарегистрирован: 29.08.2016

eto moy variant, toje rabotaet!!!

sokhib
Offline
Зарегистрирован: 29.08.2016

usrednyaet znachenie poluchennoe ot  analogRead(A5). svoego roda filtr na 10 sikla 

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Что-то такое использовал когда измерял дистанцию дальномером:

int i = 10;
int time_del = 100;
float average;

void setup() 
{
 Serial.begin(9600); 
 average = (float) i * analogRead(A5); 
}

void loop() {
     
 average = (float) (  ( (i-1)*average) + analogRead(A5)  ) / i;

Serial.println ( average);
delay(time_del); 
  }

 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017
Да что вы там курите то?


uint16_t ReadAnalogPin(const uint8_t APin) {

uint16_t result = 0;

for (uint8_t i=0; i<16; i++) {
  uint16_t val = analogRead(APin);
  if (val<10) return 0;
  if (val>1015) return 1023;
  result += val
}

 return result >> 4;
}

 

sokhib
Offline
Зарегистрирован: 29.08.2016

trembo пишет:

Что-то такое использовал когда измерял дистанцию дальномером:

int i = 10;
int time_del = 100;
float average;

void setup() 
{
 Serial.begin(9600); 
 average = (float) i * analogRead(A5); 
}

void loop() {
     
 average = (float) (  ( (i-1)*average) + analogRead(A5)  ) / i;

Serial.println ( average);
delay(time_del); 
  }

 

mojet ya chto ne ponyal!!! gde jdes sikl dlya " i "

sokhib
Offline
Зарегистрирован: 29.08.2016
10
  if (val<10) return 0;
11
  if (val>1015) return 1023

obyasnite chto delaet "return 0;" i "return 1023". vozvrawaet znachenie kuda? kak eto ispolzovat

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

это простейшая защита от дребезга.  если надо читать не аналоговые кнопки, а потенциометр эти строчки можно выкинуть

использование 

uint16_t MyPotValue = ReadAnalogPin(A1); // значение усреднено по 16-ти чтениям

Если читать надо шустрее (не знаю зачем), усреднять можно по 8 чтениям.  Но уж всяко лучше чем float тащить в память. 

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

sokhib пишет:

int val = 0;
int temp[11];
int i = 0;
int sum;
float average;
void setup() 
{
 Serial.begin(9600); 
}

void loop() {
     
for ( i=9; i>=1; i--)
{
  temp[i+1]= temp[i]; 
}
temp[1]= analogRead(A5); 
sum=0;  
for ( i=1; i<=10; i++)
{
  sum= sum + temp[i]; 
}
average= (float)sum/10.0;
 
  }
}

 

 

немного замечаний

- во-первых, в Си индексы массивов начинаются с нуля, непонятно. почему вы упорно считаете что младший элемент массива - это temp[1]

-во-вторых, если вы организуете значения в кольцевой буфер(погуглите) - вам не придется на каждом шаге двигать все значения по массиву(строчки 13-16)

- ну и в третьих - считать сумму для расчета среднего тоже можно не в отдельном цикле, а прямо в момент чтения нового значения из потенциометра

 

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

у меня под это есть класс буфера данных...

- значения хранятся в кольцевой буфере
- метод average(N) возвращает среднее за последние N значений, где N - от 4 до 10, можно использовать "на ходу". как скользящее среднее
- метод trend(N) рассчитывает наклон графика за последние N точек (тоже от 4х до 10) целочисленным методом наименьших квадратов  - это быстрый табличный МНК без сложных вычислений и без типа float

Хотя это уже, конечно, не 10 строчек....

#include <Arduino.h>
#define BUF_SIZE 16 //размер буфера - должен быть стпенью двойки
#define BUF_MASK (BUF_SIZE-1)
 
const uint8_t sum_of_numbers[] = {0,1,3,6,10,15,21,28,36,45,55}; 
const uint16_t sum_of_squares[] = {0,1,5,14,30,55,91,140,204,285,385}; 

class Data_Buffer{
  public:
  uint8_t count=0;
 
  
  void reset() {
     count =0;
     idxIN = 0;
     idxOUT = 0;
  }
  
  void put(const int val) {
     buffer[idxIN++] = val;
     idxIN &= BUF_MASK;
     if (count < BUF_MASK) count++;
  }
  
  int get() {
     if ( ! count) return -9999;
     idxOUT = idxIN - 1;
     idxOUT &= BUF_MASK;
     return  buffer[idxOUT];
  }
  
  int average(uint8_t norm) {
     long sum =0;
	 if (norm >= count) norm = count;
	 if ( ! norm) return -9999;
	 
	 idxOUT = idxIN - 1;
	 idxOUT &= BUF_MASK;
	 for (int i =0; i<norm; i++)  {
	      sum += buffer[idxOUT--];
		  idxOUT &= BUF_MASK;
		  }
	 return sum/norm;
	  
	} 
  
   int trend(uint8_t norm) {
     long sum =0;
	 if (norm > count) norm = count;
	 if (norm > 10) norm = 10;
	 if ( norm <4 ) return -9999;
	 
	 idxOUT = idxIN - 1;
	 idxOUT &= BUF_MASK;
         for (int i = norm-1; i>0; i--) {
	   sum += buffer[idxOUT--] * i;
           idxOUT &= BUF_MASK;
	  }
     return ((sum - sum_of_numbers[norm-1] * buffer[idxOUT])) / sum_of_squares[norm-1];
	 }
 
  Data_Buffer() {
   reset();
   }
  
  private:
  uint16_t buffer [BUF_SIZE];
  uint8_t idxIN, idxOUT;
  };

 

sokhib
Offline
Зарегистрирован: 29.08.2016

 

 

- во-первых, в Си индексы массивов начинаются с нуля, непонятно. почему вы упорно считаете что младший элемент массива - это temp[1]

 

[/quote]

sp za podskasku vsegda somnivalsa v etom uchus na primerax, v raznix istochnikax po raznomu obyasnyayut

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

sokhib пишет:

v raznix istochnikax po raznomu obyasnyayut

Не надо читать разные источники, надо читать Библию от Кернигана по Си и Коран от Страуструпа по С++.  

Этих двух на 80% достат.кол. 

sokhib
Offline
Зарегистрирован: 29.08.2016
Язык программирования Си
Брайан Керниган, Деннис Ритчи
3-е издание
Версия
DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

sokhib пишет:

Язык программирования Си
Брайан Керниган, Деннис Ритчи
3-е издание
Версия

Да, это чистый Си. 

sokhib
Offline
Зарегистрирован: 29.08.2016

Коран от Страуструпа???? ne ponyal, esli est podelites

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

sokhib пишет:

trembo пишет:

Что-то такое использовал когда измерял дистанцию дальномером:

int i = 10;
int time_del = 100;
float average;

void setup() 
{
 Serial.begin(9600); 
 average = (float) i * analogRead(A5); 
}

void loop() {
     
 average = (float) (  ( (i-1)*average) + analogRead(A5)  ) / i;

Serial.println ( average);
delay(time_del); 
  }

 

mojet ya chto ne ponyal!!! gde jdes sikl dlya " i "

А здесь нет никакого цикла. И нет никаких массивов.

Зачем хранить весь массив когда уже известно его среднее?

Каждое новое измерение сразу изменяет среднее. Но незначительно.

А "плавность" или " резкость" этого настраивается с помощью числа "i".

Это и есть ваш якобы размер массива.

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

ищи такую 

https://www.ozon.ru/context/detail/id/85559/

4-е издание.  На торрентах полнО.

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

разобрался )))

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

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Вот менее универсальный, но более компактный пример вычисления скользящего среднего с использованием кольцевого буфера

#define LED 1                    //светодиод
#define inputPin A1           //фоторезистор


#define BUF_SZ 16             //размер буфера для усреднения. Должен быть кратен степени 2 - 4,8,16,32,64 или 128
#define BUF_MASK (BUF_SZ-1)
uint8_t GetNextAvrg(uint8_t in)
{
    static uint8_t buf[BUF_SZ];
    static uint8_t head = 0;
    static uint8_t tail = 0;
    static uint8_t num  = 0;
    static uint16_t sum = 0;
    uint16_t ret;
   
    sum = sum + in;
    if (++num > BUF_SZ)
    {
        num = BUF_SZ;
        sum = sum - buf[tail];
        tail = ++tail & BUF_MASK;
    }
    buf[head] = in;
    head = ++head & BUF_MASK;
    //cчитаем среднее округляя результат с десятых до целого
    ret = sum * 10 / num;
    if (ret % 10 < 5)
        ret = ret / 10;
    else
        ret = ret / 10 + 1;
    return uint8_t(ret);
}

void setup() {
  pinMode(LED, OUTPUT);
}

void loop() {

  uint8_t data = analogRead(inputPin) >>2;
  analogWrite(LED, GetNextAvrg(data));
}

 

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

DetSimen пишет:

Да что вы там курите то?


uint16_t ReadAnalogPin(const uint8_t APin) {

uint16_t result = 0;

for (uint8_t i=0; i<16; i++) {
  uint16_t val = analogRead(APin);
  if (val<10) return 0;
  if (val>1015) return 1023;
  result += val
}

 return result >> 4;
}

для 12 бит тоже подойдёт!?

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

ua6em пишет:

для 12 бит тоже подойдёт!?

если число значений не больше 16, то да. 

rkit
Offline
Зарегистрирован: 23.11.2016

b707 пишет:

- метод trend(N) рассчитывает наклон графика за последние N точек (тоже от 4х до 10) целочисленным методом наименьших квадратов  - это быстрый табличный МНК без сложных вычислений и без типа float

Заинтересовал меня этот чудо-алгоритм, и чет он не работает совсем.

https://ideone.com/d12G2A

Показывает 0 для последовательности 5 6 7 0, когда лучший целочисленный -1, с суммой квадратов 21 против 30 для 0. Совсем точный ответ -1.4, так что лаже -2 гораздо лучше 0.

Можно рассказать, откуда этот алгоритм вообще взялся?

-NMi-
Offline
Зарегистрирован: 20.08.2018

Что с ним не так?

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

-NMi- пишет:

Что с ним не так?

Прверил, да, к сожалению rkit прав.

логическая ошибка в рассуждениях. Алгоритм описывает данные уравнением

y = a*x,

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

  y = a*x + b

-NMi-
Offline
Зарегистрирован: 20.08.2018

Дык давай сделаем, чо?  Алгоритм есть? Формулы?

Делов-то...))))