Simple-Scada forum

Simple-Scada 2 => Ваши вопросы => Тема начата: razorqhex от 28 Января 2020, 13:06:55

Название: Функция ArchiveValueByTime и ошибка NAN
Отправлено: razorqhex от 28 Января 2020, 13:06:55
Здравствуйте. Раннее в теме "Расчёт удельной потребляемой мощности" я писал о том, что функция ArchiveValueByTime иногда пишет ошибку NAN после расчётов. Я думал, что исправил, но за сутки довольно таки много раз попадается ошибка NAN, а если значение переменной перевести в строку, то будет ошибка INF.

Ошибка происходит именно в расчёте удельной потребляемой мощности. Эта функция ещё используется в расчётах суточной воды и часовой, но там всё в порядке и никаких ошибок не было.

Скрипт который выполняется каждый час:

Код: (delphi)
var
  aDateSpecPower: TDateTime;
begin

  //Удельная потребляемая мощность ВНС 19
  aDateSpecPower := RecodeTime(Now, HourOf(Now), MinuteOf(Now), 0, 0);
  ArchiveValueByTime(kWh_Counter_19, SpecificPowerConsumption_VNS19_End, aDateSpecPower);

  aDateSpecPower := IncHour(Now, -1);
  ArchiveValueByTime(kWh_Counter_19, SpecificPowerConsumption_VNS19_Start, aDateSpecPower);

end.

Скрипт "Изменилась переменная". Он срабатывает по тегам SpecificPowerConsumption_VNS19_End и SpecificPowerConsumption_VNS19_Start

Код: (delphi)
begin
  SPC_VNS19.Value := SpecificPowerConsumption_VNS19_End.Value - SpecificPowerConsumption_VNS19_Start.Value;
  //Вычисляем удельную потребляемую мощность ВНС19
  SpecificPowerConsumption_VNS19_Result.Value := SPC_VNS19.value / HourlyWaterConsumption_VNS19_Result.Value;
end.

Потом бывает очень странный график (красная линия)

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

Расчёты суточной воды и часовой абсолютно одинаковы вместе с расчётом удельной потребляемой мощности, но меняются в расчётах только теги.
Название: Re: Функция ArchiveValueByTime и ошибка NAN
Отправлено: Simple-Scada от 28 Января 2020, 13:48:50
Здравствуйте.

Цитировать
Я думал, что исправил, но за сутки довольно таки много раз попадается ошибка NAN
Какая именно переменная у Вас становится равна NAN? В этой теме (https://simple-scada.com/forum/index.php?topic=949.msg8081#msg8081) Вы писали, что это переменная "SpecificPowerConsumption_VNS19_Result". Тогда причём здесь процедура "ArchiveValueByTime"? Пожалуйста, разберитесь немного в собственном коде, подумайте что, когда и как вычисляется, исключите ситуации с делением на ноль (на ноль делить нельзя). Если взять переменную "SpecificPowerConsumption_VNS19_Result", то она в Вашем коде вычисляется так:
Код: (delphi)
SpecificPowerConsumption_VNS19_Result.Value := SPC_VNS19.value / HourlyWaterConsumption_VNS19_Result.Value;
т.е. в неё записывается результат деления двух чисел. А процедура "ArchiveValueByTime" здесь не при чем. В коде Вы не проверяете является ли делитель нулём или нет. Если он ноль, то результат конечно будет NAN, т.к. на ноль делить нельзя. Поэтому перед присвоением следует убедиться в том, что делитель не является нулём. Это очень просто:
Код: (delphi)
if HourlyWaterConsumption_VNS19_Result.Value <> 0 then 
  SpecificPowerConsumption_VNS19_Result.Value := SPC_VNS19.value / HourlyWaterConsumption_VNS19_Result.Value;

Цитировать
Ошибка происходит... то будет ошибка INF.
Ошибки не происходит вовсе. Всё работает строго в соответствии с тем кодом, который Вы написали.

Цитировать
Ошибка происходит именно в расчёте удельной потребляемой мощности.
Из этого следует очень простой вывод: у Вас деление на ноль происходит только в расчёте удельной потребляемой мощности. Если бы деления на ноль не было, то и "ошибки" тоже не было бы.
Название: Re: Функция ArchiveValueByTime и ошибка NAN
Отправлено: razorqhex от 28 Января 2020, 15:16:41
Вы писали, что это переменная "SpecificPowerConsumption_VNS19_Result". Тогда причём здесь процедура "ArchiveValueByTime"?
Да, Вы правы. Функция ArchiveValueByTime здесь не причем.
Цитировать
Если бы деления на ноль не было, то и "ошибки" тоже не было бы.
В том то и дело, что деления на ноль не происходит.
Переменная HourlyWaterConsumption_VNS19_Result вычисляется самой первой и в ней всегда есть значение. Это переменная хранит значение суточного расхода воды.

Я согласен с тем, что как-то, где-то происходит деление на ноль и из-за чего я вижу NAN, но я все теги вывожу и вижу, что в ключевых тегах есть значение
Название: Re: Функция ArchiveValueByTime и ошибка NAN
Отправлено: Simple-Scada от 28 Января 2020, 20:56:49
Цитировать
но я все теги вывожу и вижу, что в ключевых тегах есть значение
Через код в скриптах можно изменить значение переменной например 1 млн. раз в секунду. Но Вы увидите только последнее значение. Нет смысла определять на глаз. Если Вы видите значение NAN, значит переменная была поделена на ноль. У Вас деление на ноль будет обязательно выполняться при каждом запуске проекта (как минимум), т.к. в момент инициализации проекта в переменные записываются нули.

Цитировать
В том то и дело, что деления на ноль не происходит.
Скада-система это обычная скомпилированная программа, как Калькулятор и т.п. приложения, она не может не разделив на ноль получить NAN и работает всегда одинаково. Она не будет в произвольный момент времени сама по себе записывать NAN (или какие-либо другие произвольные значения) в переменную, или делать какие-то другие "чудеса", т.к. для этого нам пришлось бы написать такой алгоритм присвоения NAN. Странно, что об этом вообще приходится писать.

Цитировать
Я согласен с тем, что как-то, где-то происходит деление на ноль и из-за чего я вижу NAN
Именно. И есть только одно место в котором может производиться деление переменной - это скрипты, в которых выполняется её деление.

Если у Вас никак не получается разобраться с тем, как выполняется деление и скрипты, то вышлите проект нам на support@simple-scada.com, мы проверим Ваш проект и напишем где и когда выполняется деление на ноль. Из той информации что у нас есть сейчас, деление очевидно выполняется в коде:
Цитировать
SpecificPowerConsumption_VNS19_Result.Value := SPC_VNS19.value / HourlyWaterConsumption_VNS19_Result.Value;
, т.к. другого кода с делением нет.

На самом деле, учитывая количество потраченного времени на такую простую проблему, уже давно можно было бы проверить имеющийся код, например просто на одни сутки изменить код скрипта вот так:
Цитировать
SpecificPowerConsumption_VNS19_Result.Value := SPC_VNS19.value / 1;
и если NAN перестанет возникать, то значит дело на 100% именно в этом конкретном скрипте и значит на 100% переменная HourlyWaterConsumption_VNS19_Result бывает равна нулю. Тогда не придётся угадывать или предполагать магическое деление. Если NAN все равно будет возникать, значит дело на 100% в чем-то другом и т.д.