Усреднение нескольких рядов данных через одну функцию

Есть две термопары , на них есть “шум”, соответственно необходимо усреднение. Для понимания данных во времени хочу усреднять не по количеству измерений, а за период, допустим за секунду. Вот мой вариант

void readPin_AveragePerPeriod(uint16_t period){ //среднее за период в мсек
  static uint32_t timer, count;  //таймер для подсчета прошла ли секунда и счетчик для подсчета количества измерений
  static float avg_sum, avg;   //накопительная сумма измерений и средняя
  if (millis()-timer>=period){   //если прошла секунда с прошлого вывода данных
    timer = millis();  //обнуляем таймер
    avg = avg_sum/count;  //среднее значение
    Serial.println(avg);
    avg_sum = 0;  //обнуляем
    count = 0;
  }
  else{   //если секунда не прошла, только обновляем переменные
    count++;
    avg_sum += analogRead(ValueOUT)*voltageIN/1024;
  }
}

Пока брал показания с одного датчика все понятно, сейчас стал вопрос второго и не могу понять как корректно делать дальше. Проще всего сделать func1 и func2 полностью идентичные, учитывая что переменные объявлены внутри ничего и менять не нужно, но хотелось бы разобраться есть ли “правильный” способ(мне лично хотелось бы короткого и удобно читаемого варианта), к тому же есть в планах добавить еще несколько измерений. Получается что при вызове функции она считает 3 переменные и один раз в секунду выдает 4-ую. Пока склоняюсь к тому, чтобы объявить на каждый пин массив и обновлять там данные, т.е. при каждом вызове функции брать их, обрабатывать и обновлять их в массиве, а по истечении секунды выдавать среднюю. правильно ли так делать с точки зрения “основ”?

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

Не не не. Фигню я написал.
Надо саму функцию переделывать под разные данные.

Я с датчика растояния часто беру значение и храню последние 10, по ним вычисляю среднее значение.

S23 а это полезная фича! я сам ее подрезал когда какой то курс проходил, и в датчиках температуры видел ее, а так же датчиках веса, не уверен что через функцию, но полезная!

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

мне “дешевле” хранить кумулятивную сумму и количество замеров, всего две переменные, раз в секунду считать среднюю и обнулять их

Нереально много, ты не ошибся?

чуток ошибся, это я в начале смотрел, было 6, вывел сейчас в печать count(количество замеров) 3600. Это вроде нормально или нет? она в каждом loop же вызывается. мне пока незачем ее ограничивать

а подскажите пж мой ЫЫ угадал ?

ты лучше скажи что они меряют и зачем ?)))

Ха! Теперь самый интересный вопрос! :grinning_face_with_smiling_eyes:

Давай представим, что могут измерять две термопары и зачем им усреднение:

Вариант 1: Научный/Лабораторный

  • Одна термопара меряет температуру объекта (например, реактива в колбе)

  • Вторая меряет температуру окружающей среды (компенсация холодного спая)

  • Зачем усреднение: Термопары дают очень маленькое напряжение (мкВ), которое легко “шумит” от сетевых наводок, моторов и т.д.

Вариант 2: Промышленный контроль

  • Датчик 1: Температура входящего теплоносителя

  • Датчик 2: Температура исходящего теплоносителя

  • Зачем: Разность температур показывает эффективность теплообменника или работы котла

Вариант 3: Холодильная установка

  • Датчик 1: Температура испарителя (холод)

  • Датчик 2: Температура конденсатора (горячо)

  • Зачем: Контролировать цикл охлаждения и вовремя обнаруживать обледенение или утечку фреона

Вариант 4: Метеостанция (но термопары - странно)

  • Термопара 1: Температура воздуха

  • Термопара 2: Температура почвы/воды

  • Зачем: Термопары быстрее реагируют на изменения, чем термисторы

Вариант 5: Печь/Термостат

  • Датчик 1: Температура нагревателя (для быстрого отклика)

  • Датчик 2: Температура объекта (по которому стабилизируем)

  • Зачем: Чтобы не перегреть объект, управляя мощным нагревателем

Вариант 6: Химический реактор

  • Термопара в рубашке: Температура теплоносителя

  • Термопара в реакционной массе: Температура реакции

  • Зачем: Экзотермическая реакция может выйти из-под контроля

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

dmitriy_8 а можно еще вопрос ?)) а зачем вы так много измеряете ?
а что будет если код большой будет скорость измерения сразу просядет ?
это все 1 вопрос!)))

Если напряжение с датчика пропорционально температуре, то нужно суммировать 64 (влезет в uint16_t) значений АЦП (для AVR), а затем переводить в температуру.

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

это наверное я не так понял код)))

// Структура для хранения состояния канала измерения
struct SensorChannel {
  uint8_t pin;           // пин, к которому подключен датчик
  uint32_t count;        // счетчик измерений за период
  float sum;             // сумма значений за период
  float lastAverage;     // последнее вычисленное среднее
  
  // Конструктор для удобной инициализации
  SensorChannel(uint8_t p) : pin(p), count(0), sum(0.0), lastAverage(0.0) {}
};

// Создаем массив датчиков
SensorChannel sensors[] = {
  SensorChannel(34),  // первый датчик на пине 34
  SensorChannel(35)   // второй датчик на пине 35
};

const int numSensors = sizeof(sensors) / sizeof(sensors[0]);
uint32_t lastPrintTime = 0;  // единый таймер для всех

void setup() {
  Serial.begin(115200);
}

void loop() {
  // Читаем ВСЕ датчики при каждом проходе loop
  for (int i = 0; i < numSensors; i++) {
    float voltage = analogRead(sensors[i].pin) * voltageIN / 1024.0;
    sensors[i].sum += voltage;
    sensors[i].count++;
  }
  
  // Проверяем, не пора ли вывести результаты (раз в период)
  if (millis() - lastPrintTime >= 1000) {  // период 1000 мс
    lastPrintTime = millis();
    
    // Выводим данные всех датчиков синхронно
    Serial.print("Время: "); Serial.print(millis());
    for (int i = 0; i < numSensors; i++) {
      if (sensors[i].count > 0) {
        sensors[i].lastAverage = sensors[i].sum / sensors[i].count;
        Serial.print(" | Д");
        Serial.print(i + 1);
        Serial.print(": ");
        Serial.print(sensors[i].lastAverage, 3);
        
        // Сбрасываем счетчики
        sensors[i].sum = 0;
        sensors[i].count = 0;
      }
    }
    Serial.println();
  }
}

а еще вы тут о каких то 3600 измерениях говорите… в общем вот от ии, может пригодится

1 лайк

если Вы про float, то я пока перевожу в вольты: 1) могу вольтметром перепроверить правильность показаний, 2) пока не готов переводить в градусы, не всю цепь нарисовал, надо разобрать какой ток изначально в цепи и сколько сопротивления на плате, без этого не могу знать точное сопротивление на термопаре, это дело времени, но сейча не готов

надо пробовать, вроде бы оно))

это 10 из 10)) то что надо, спасибо! можно фоторезистор на обнаружение пламени ставить.

а что Вы имели ввиду “…от ИИ”?

да от ЫЫ, это мой помощник, он делает все за меня, но под моим чутким руководством!

Нет

можно хоть чуть подробнее? интересно

В качестве эксперимента. Создай массив 3600. Заполни его данными с датчика. Посчитай среднее по 8 - 16-32-64 … 2048 точек и посмотри как меняется результат. Может оказаться что усреднение по 32 точкам достаточно и дальнейшее увеличение точек в усреднении бесполезный перевод ресурсов и времени.

1 лайк