PDA

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



KoryaevAN
14.04.2020, 14:04
Доброго здоровья!
MasterSCADA 3.11
Есть необходимость вывести на мнемосхему текущую и скользящие: среднюю, максимальную, минимальную температуры наружного воздуха. Интервал расчета изменяемый (до недели).
Функциональные блоки "Скользящее среднее", "Скользящий максимум" и "Скользящий минимум" сбрасывают накопленные расчеты при перезапуске или при изменении интервала.
Функциональные блоки "Дискретное среднее", "Дискретный максимум" и "Дискретный минимум" не подходят, кроме того ведут себя так же.
Со средним значением выход нашелся применением функции в расчете AbsArchAverageValue(Значение, DateTime( )-Интервал, DateTime( )). А что можно применить для вытаскивания из архива максимального и минимального значений?
Пробный проект во вложении.

SCADAMaster
14.04.2020, 14:28
В расчетах нет возможности извлечения максимума и минимума из архива. Плюс то как вы сейчас делали - постоянно опрашиваете Расчет, будет сильно грузить систему, так как приходится постоянно обращаться к архиву. Если конечно проект не большой, то это не критично.
Вам все же лучше использовать ФБ "Скользящее среднее", просто попробовать в настройках ФБ на вкладке Опрос включить Восстановление при рестарте.

KoryaevAN
14.04.2020, 15:58
Проект большой :(
Опрос можно сделать и реже, раз в 10-15 мин, некритично.
А с максимумом и минимумом печалька. Архивация значения ведется в MSSQL. Может там что то можно сделать (процедура, функция)?

SCADAMaster
14.04.2020, 16:21
Можно скриптом
https://insat.ru/blog/fb-skript-c-i-ego-ispolzovanie-v-masterscada-obrabotka-arkhivov/
Но лучше все же ФБ

KoryaevAN
17.04.2020, 14:15
Доработал скрипт. Вроде работает.
Не смог воткнуть в него Аverage. Пришлось среднее считать по простому. Может, кто то предложит более правильный вариант?

SCADAMaster
17.04.2020, 14:45
По правильному - считать интегральное среднее. Считаете интеграл - площадь фигуры, ограниченной интервлом и значениями сверху. Можно считать прямоугольниками - высота прямоугольника значение величины в момент времени, ширина - значение в секундах до следующего значения. Суммируете все, и делите на количество секунд за этот интервал.

KoryaevAN
20.04.2020, 09:25
Всё это правильно. Но, для меня, проблема как реализовать это в коде скрипта. Я электронщик, программиста нет, поэтому приходится самому этим заниматься.
Как я понимаю, если архив записывается с переменной которая опрашивается периодически, то разницы нет среднее или интегральное среднее?
А если архив записывается с переменной которая опрашивается по изменению значения, то надо использовать интегральное среднее?
Сейчас я в цикле foreach подсчитываю сумму значений, количество значений и считаю среднее.
Вопрос в том, как правильно записать вычисление среднего (интегрального среднего) в коде скрипта с точки зрения нормального программиста, а не такого почти дилетанта как я.

using System;
using MasterSCADA.Script.FB;
using MasterSCADA.Hlp;
using FB;
using System.Linq;

public partial class ФБ : ScriptBase
{
bool? M=false;
public override void Execute()
{
if (Найти==true && M==false && Начало.HasValue && Конец.HasValue && Конец>Начало)
{
var elem = HostFB.InputGroup.GetPin("Вход").TreePinHlp;
var k=elem.DataArchiveItem;

DateTime EndTime=Конец.Value.ToUniversalTime();
DateTime StartTime=Начало.Value.ToUniversalTime();
var mas=k.Read(StartTime, EndTime, false);
double? Max=null;
double? Min=null;
double? Avg=null;
double? sum=0;
double? num=0;
DateTime? TimeStampMax=null;
DateTime? TimeStampMin=null;

foreach (var element in mas)
{
if (Max.HasValue==false || Convert.ToDouble(element.Value)>Max.Value)
{
Max=Convert.ToDouble(element.Value);
TimeStampMax=element.Time.ToLocalTime();
}
if (Min.HasValue==false || Convert.ToDouble(element.Value)<Min.Value)
{
Min=Convert.ToDouble(element.Value);
TimeStampMin=element.Time.ToLocalTime();
}

sum=sum + Convert.ToDouble(element.Value);
num=num + 1;
}
Avg=sum / num;
Максимум=Max;
МеткаВремениМаксимум=TimeStampMax;
Минимум=Min;
МеткаВремениМинимум=TimeStampMin;
Среднее=Avg;
}
M=Найти;
}
}

SCADAMaster
20.04.2020, 09:49
Как я понимаю, если архив записывается с переменной которая опрашивается периодически, то разницы нет среднее или интегральное среднее?
А если архив записывается с переменной которая опрашивается по изменению значения, то надо использовать интегральное среднее?

Да.

У вас в принципе все сделано.
Осталось только интеграл найти. С высотой прямоугольника, я думаю все понятно.
Ширина - разница между точками. Сохраняйте в переменную значение метки времени с прошлого выполнения цикла foreach. И вычитаете из текущего:
var diff = (dateTime1 - dateTime2).TotalSeconds;
Умножаете на высоту, суммируете. В конце делите на общее количество секунд между двумя интервалами.