Усреднение обрабатываемых данных

Стартовая страница Форумы Понять, как работает ПО Усреднение обрабатываемых данных

Просмотр 15 сообщений - с 1 по 15 (из 18 всего)
  • Автор
    Сообщения
  • #8056
    Danila_Razlivanov
    Участник

    Доброго времени суток. Возник такой вопрос, есть ли возможность посчитать среднее значение получаемого параметра, скажем, за сутки? То есть, в зависимости от изменения, к примеру, расхода, изменяется количество твердого в перекачиваемой жидкости. Т.к. в разные моменты времени, опять же в зависимости от расхода, значение расчитываемой величины (количества твердого) будем меняться, есть необходимость обсчитать это значение, к примеру, за сутки. Подскажите, есть ли такая возможность, и какие варианты её реализации? Заранее благодарен.

    #8058
    Mikhail
    Модератор

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

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

    #8059
    Mikhail
    Модератор

    Примеры формул для аналогичной задачи:

    // Среднее значение за период
    double PerAvg(int sumCnlNum, int cntCnlNum)
    {
      if (Stat() == 2) // архивный
      {
        return Val();
      }
      else
      {
        double sum = Val(sumCnlNum);
        double cnt = Val(cntCnlNum);
        return cnt < 1 ? 0 : sum / cnt;
      }
    }
    
    // Статус среднего значения за период
    double PerAvgStat(int cntCnlNum)
    {
      return Stat() == 2 ? 2 : 
        (Val(cntCnlNum) < 1 ? 0 : 1);
    }
    
    // Обработать полученное от контроллера значение
    double ProcVal(double coef, params int[] sumCnlNums)
    {
      double cur = Cnl >= 0 ? Cnl * coef : 0;
      foreach (int sumCnlNum in sumCnlNums)
      {
        int cntCnlNum = sumCnlNum + 1;
        double newSum = Val(sumCnlNum) + cur;
        double newCnt = Val(cntCnlNum) + 1;
        SetVal(sumCnlNum, newSum);
        SetVal(cntCnlNum, newCnt);
      }
      return cur;
    }
    
    // Обнулить значение в начале суток
    double ResetOnDayBeg()
    {
      return DayBeg() ? 0 : Val();
    }
    
    #11454
    baur
    Участник

    Всем привет,
    1)
    как можно эту формулу переделать в счетчик который не сбрасывается

    2)

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

    то есть создаем 2 канала (минутный ТС, часовой ТС), формула = Val(нужный номер канала) + галочка усреднение?

    #11455
    baur
    Участник

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

    • Этот ответ был изменен 5 лет, 10 месяцев назад от baur.
    #11459
    Mikhail
    Модератор

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

    #36118
    Aeromixture
    Участник

    Не совсем понятно как использовать этот код. Если копировать весь класс то он не помещается в ограничение в 4000 символов. Если копировать часть кода ничего не работает.

    #36119
    a80808
    Участник

    Вам это нужно на экране или в отчете? Гибкий отчет сам считает среднее. Как вариант суммировать в какой то канал значения, например каждый час, а потом раз в сутки делить это на 24
    Это все для 5.8, в шестерке должно быть проще…

    #36166
    Mikhail
    Модератор

    Код выше подразумевает, что Вы завели 2 дополнительных расчётных канала:
    — Для суммы значений.
    — Для количества значений.

    Этот подход удобен, когда величин для расчёта средних значений не так много.
    Код для версии 5. Для версии 6 его нужно немного доработать.

    #36167
    Mikhail
    Модератор

    Да, как вариант — гибким отчётом посчитать среднее за период отчёта.

    #36168
    Mikhail
    Модератор

    Расскажите подробнее про свою задачу, чтобы было понятнее как её удобнее решать.

    #36185
    Aeromixture
    Участник

    Нужно среднее значение за промежуток времени. Конкретно за прошедший день и месяц.

    #36186
    Aeromixture
    Участник

    Нужно выводить на экран среднее значение за сутки и месяц. Не скользящее среднее.

    #36187
    a80808
    Участник

    Суммировать в канале, потом делить на число измерений
    Вот я делал для другого проекта (правда версия 5, но можно переделать):
    «…

    На стороне Scada была реализована следующая схема:
    1. (3210) Канал ТС принимающий состояния входа, определяющего работу насоса (0/1) – Событие/Текст перечисления/Вкл-Откл/Запись событий/Событие по изменению;
    2. (60081) (Минутный ТИ) Канал, подсчитывающий мнгновенную (минутную) производительность (подачу), т.е. если насос включен — значение канала равно константе производительности, выключен = 0 (Val(3210)==0?(100*0.8):0);
    3. (60100) (Дорасчетный ТИ) Канал, подсчитывающий суммарную подачу, т.е. суммирует подачу всех насосов одной насосной;
    4. Дальше идет блок каналов суммирования за определенный период:
    a. (60103) (Дорасчетный ТИ) – с начала дня (здесь формула, о ней ниже);
    b. (60104) (Дорасчетный ТИ) – за предыдущий день;
    c. (60105) (Дорасчетный ТИ) – с начала месяца;
    d. (60106) (Дорасчетный ТИ) – за предыдущий месяц;
    e. (60107) (Дорасчетный ТИ) – с начала года.
    Теперь о формуле. В канале Ежедневного расхода написана формула (вызов) для подсчета и заполнения каналов, указанных выше:
    CalcRate(60103,60104,60105,60106,60107,60100)
    Текст формулы ниже:

    double CalcRate(int cnl_today, int cnl_yesterday, int cnl_month, int cnl_prevmonth, int cnl_begyear, int cnl_src)
    {
    double cnl_sum;
    DateTime nowDT = DateTime.Now;
    if (DayBeg() == true)
    {
    if (MonthBeg() == true)
    {
    SetVal(cnl_prevmonth, Val(cnl_month));
    if (nowDT.Month == 1 && nowDT.Day == 1)
    {
    SetVal(cnl_begyear, 0);
    }
    SetVal(cnl_month,0);
    }
    SetVal(cnl_yesterday, Val(cnl_today));
    SetVal(cnl_month, (Val(cnl_month) + Val(cnl_today)));
    SetVal(cnl_begyear, (Val(cnl_begyear) + Val(cnl_today)));
    SetVal(cnl_today, 0);
    }
    cnl_sum = (Val(cnl_today) + Val(cnl_src)/60);
    return cnl_sum;
    }

    Используются «штатные» DayBeg(), MonthBeg() и довольно топорное определение №начала года». Т.е. впри наступлении одного или нескольких сразу событий начала периода :
    -Значение расхода за сегодня переписывается в канал «за вчера»;
    -В значение «с начала месяца» добавляется «за сегодня»
    — Канал «за сегодня» обнуляется.
    Ну и также для начала месяца и года…

    #36192
    Mikhail
    Модератор

    Нужно выводить на экран среднее значение за сутки и месяц. Не скользящее среднее.

    Вариант 1.
    Считать среднее по тем значениям, которые хранятся в историческом архиве. Сейчас это умеет делать плагин Гибкий отчёт. Было бы полезно разработать модуль для Сервера, чтобы делал вычисления и записывал результат в канал для среднего.

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

    Вам какой вариант подходит больше?

    • Этот ответ был изменен 2 месяца назад от Mikhail.
Просмотр 15 сообщений - с 1 по 15 (из 18 всего)
  • Вы должны авторизироваться для ответа в этой теме.