Вход

Просмотр полной версии : Управлене 2 насосами через ПЧ



Биба
11.10.2024, 12:03
есть 2 ПЧ управляющие 2 насосами на подъемной станции холодного водоснабжения. Сейчас на каждом из них настроен ПИД регулятор и к каждому подключен свой датчик давления. Заказчику кажется это варварством и он хочет автоматизацию(но по дешевле). предложил ему ПР200 с аналоговыми выходами.
Суть вопроса:
Написал ФБ для этих ПЧ и вроде все нормально работет, но вот в части логики переключения насосов, как мне кажется, перемудрил но ничего более адекватного родить не смог.
Найдутся ли господа которы бы помогли переработать код и сделать его изящней?


FUNCTION_BLOCK PID_Controller_
var_input
Run: bool; // разрешение на работу
Setpoint: real; // Уставка (целевое значение)
Feedback: real; // Входной сигнал обратной связи (4-20 мА)
Kp: real; // Пропорциональный коэффициент
Ki: real; // Интегральный коэффициент
Kd: real; // Дифференциальный коэффициент
Maxdat: real; // предел датчика 4-20
Frequency: udint; // вход для времени дискретизации (мс)
AlarmFM1: bool; // NС контакт ошибки ПЧ
AlarmFM2: bool; // NС контакт ошибки ПЧ
Time_Pump: udint; // время смены основного насоса (ч)
low_inlet_press: bool; // защита от сухого хода (NC)
which_pump: udint:= 0; // выбор работы: 0- оба насоса со сменой; 1-только 1 насос; 2-только 2 насос; 3- оба насоса без смены 1 основной; 4- оба насоса без смены 2 основной
end_var

var_output
ScaledOutput : real; // Масштабированный выходной сигнал в бар
FM1: real; // выходной сигнал на AO1
FM2: real; // выходной сигнал на AO2
AlarmOut_b: bool; // красный светодиод
AlarmOut_U: udint; // переменная на экран: 0- нет аварий; 1-авария 1 насоса; 2-авария 2 насоса; 3-сухой ход; 4- авария обоих насосов
end_var

var
Error: real; // Ошибка
PreviousError: real:= 0.0; // Предыдущая ошибка
Integral: real:= 0.0; // Интегральная составляющая
Derivative: real; // Дифференциальная составляющая
MinOutput: real:= 0; // Минимальное значение выходного сигнала
MaxOutput: real:= 1; // Максимальное значение выходного сигнала
TP_1: SYS.TP;
OutputSignal_RAW: real; // не масштабированный входной сигнал обратной связи
OutputSignal_LOW: real; // масштабированный входной сигнал обратной связи для основного/единственного насоса
OutputSignal_HIGH: real; // масштабированный входной сигнал обратной связи для резевного насоса
T_time: time;
PumpSw: SYS.blink;
switch_Pump: bool; // основной/резервный по времени
Time_switch: time;
pip: bool; // разрешение на вычисление
end_var

T_time:= udint_to_time(Frequency);
Time_switch:= udint_to_time(Time_Pump*3600000);
ScaledOutput := ((Feedback-4)*MaxOutput)/16 ; // Масштабирование

if Run then // генератор импульса
TP_1(I:= not pip, T:= T_time, Q => pip);
else
TP_1(I:= false);
pip:= false;
OutputSignal_RAW:= 0;
end_if

if pip and Run then
OutputSignal_RAW:= OutputSignal_RAW;
elsif not pip and Run then // Вычисление ошибки с масштабированием входного сигнала (4-20 мА)
Error:= Setpoint - ScaledOutput; // расчет ошибки
Integral:= Integral + Error; // Интегральная составляющая
Derivative:= Error - PreviousError; // Дифференциальная составляющая
OutputSignal_RAW:= Kp * Error + Ki * Integral + Kd * Derivative; // Вычисление выходного сигнала
PreviousError:= Error; // Сохранение текущей ошибки для следующего шага
elsif not Run then
OutputSignal_RAW:= 0;
end_if

OutputSignal_LOW:= OutputSignal_RAW/100; // масштабирование для АО
IF OutputSignal_LOW < MinOutput then // ограничение от 0 до 1
OutputSignal_LOW:= MinOutput;
elsif OutputSignal_LOW > MaxOutput then
OutputSignal_LOW:= MaxOutput;
end_if

OutputSignal_HIGH:= (OutputSignal_RAW-100)/100; // масштабируем для АО
IF OutputSignal_HIGH < MinOutput then // ограничение от 0 до 1
OutputSignal_HIGH:= MinOutput;
elsif OutputSignal_HIGH > MaxOutput then
OutputSignal_HIGH:= MaxOutput;
end_if
// логика насосов
if AlarmFM1 and AlarmFM2 and low_inlet_press then // если нет ошибок
AlarmOut_b:= false;
AlarmOut_U:= 0;
if Run and which_pump= 0 then // стандартный режим
PumpSw (I:= true,Th:= Time_switch,Tl:= Time_switch,Q=>switch_Pump);
if switch_Pump then
FM1:= OutputSignal_LOW;
FM2:= OutputSignal_HIGH;
else
FM2:= OutputSignal_LOW;
FM1:= OutputSignal_HIGH;
end_if

elsif run and which_pump= 1 then
FM1:= OutputSignal_LOW;
FM2:= 0;
elsif run and which_pump= 2 then
FM1:= 0;
FM2:= OutputSignal_LOW;
elsif run and which_pump= 3 then
FM1:= OutputSignal_LOW;
FM2:= OutputSignal_HIGH;
elsif run and which_pump= 4 then
FM1:= OutputSignal_HIGH;
FM2:= OutputSignal_LOW;
else
FM1:= 0;
FM2:= 0;
PumpSw (I:= false);
end_if
// реакции на ошибки
elsif not AlarmFM1 and not AlarmFM2 and low_inlet_press then // авария 1 и 2 насоса
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 4;//

elsif not AlarmFM1 and low_inlet_press then // авария 1 насоса
if Run then
if which_pump= 0 or which_pump>= 2 then
FM1:= 0;
FM2:= OutputSignal_LOW;
AlarmOut_b:= true;
AlarmOut_U:= 1;//
elsif which_pump= 1 then
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 1;//
elsif which_pump= 2 then
FM1:= 0;
FM2:= OutputSignal_LOW;
AlarmOut_b:= false;
AlarmOut_U:= 0;//
end_if

elsif not run and which_pump= 2 then
FM1:= 0;
FM2:= 0;
AlarmOut_b:= false;
AlarmOut_U:= 0;//
else
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 1;//
end_if

elsif not AlarmFM2 and low_inlet_press then // авария 2 насоса
if Run then
if which_pump= 0 or which_pump>= 3 then
FM1:= OutputSignal_LOW;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 2;//
elsif which_pump= 2 then
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 2;//
elsif which_pump= 1 then
FM1:= OutputSignal_LOW;
FM2:= 0;
AlarmOut_b:= false;
AlarmOut_U:= 0;//
end_if

elsif not run and which_pump= 1 then
FM1:= 0;
FM2:= 0;
AlarmOut_b:= false;
AlarmOut_U:= 0;//
else
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 2;//
end_if

elsif not low_inlet_press then // сухой ход
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 3;//
end_if

END_FUNCTION_BLOCK

Сергей0308
11.10.2024, 13:48
есть 2 ПЧ управляющие 2 насосами на подъемной станции холодного водоснабжения. Сейчас на каждом из них настроен ПИД регулятор и к каждому подключен свой датчик давления. Заказчику кажется это варварством и он хочет автоматизацию(но по дешевле). предложил ему ПР200 с аналоговыми выходами.
Суть вопроса:
Написал ФБ для этих ПЧ и вроде все нормально работет, но вот в части логики переключения насосов, как мне кажется, перемудрил но ничего более адекватного родить не смог.
Найдутся ли господа которы бы помогли переработать код и сделать его изящней?


FUNCTION_BLOCK PID_Controller_
var_input
Run: bool; // разрешение на работу
Setpoint: real; // Уставка (целевое значение)
Feedback: real; // Входной сигнал обратной связи (4-20 мА)
Kp: real; // Пропорциональный коэффициент
Ki: real; // Интегральный коэффициент
Kd: real; // Дифференциальный коэффициент
Maxdat: real; // предел датчика 4-20
Frequency: udint; // вход для времени дискретизации (мс)
AlarmFM1: bool; // NС контакт ошибки ПЧ
AlarmFM2: bool; // NС контакт ошибки ПЧ
Time_Pump: udint; // время смены основного насоса (ч)
low_inlet_press: bool; // защита от сухого хода (NC)
which_pump: udint:= 0; // выбор работы: 0- оба насоса со сменой; 1-только 1 насос; 2-только 2 насос; 3- оба насоса без смены 1 основной; 4- оба насоса без смены 2 основной
end_var

var_output
ScaledOutput : real; // Масштабированный выходной сигнал в бар
FM1: real; // выходной сигнал на AO1
FM2: real; // выходной сигнал на AO2
AlarmOut_b: bool; // красный светодиод
AlarmOut_U: udint; // переменная на экран: 0- нет аварий; 1-авария 1 насоса; 2-авария 2 насоса; 3-сухой ход; 4- авария обоих насосов
end_var

var
Error: real; // Ошибка
PreviousError: real:= 0.0; // Предыдущая ошибка
Integral: real:= 0.0; // Интегральная составляющая
Derivative: real; // Дифференциальная составляющая
MinOutput: real:= 0; // Минимальное значение выходного сигнала
MaxOutput: real:= 1; // Максимальное значение выходного сигнала
TP_1: SYS.TP;
OutputSignal_RAW: real; // не масштабированный входной сигнал обратной связи
OutputSignal_LOW: real; // масштабированный входной сигнал обратной связи для основного/единственного насоса
OutputSignal_HIGH: real; // масштабированный входной сигнал обратной связи для резевного насоса
T_time: time;
PumpSw: SYS.blink;
switch_Pump: bool; // основной/резервный по времени
Time_switch: time;
pip: bool; // разрешение на вычисление
end_var

T_time:= udint_to_time(Frequency);
Time_switch:= udint_to_time(Time_Pump*3600000);
ScaledOutput := ((Feedback-4)*MaxOutput)/16 ; // Масштабирование

if Run then // генератор импульса
TP_1(I:= not pip, T:= T_time, Q => pip);
else
TP_1(I:= false);
pip:= false;
OutputSignal_RAW:= 0;
end_if

if pip and Run then
OutputSignal_RAW:= OutputSignal_RAW;
elsif not pip and Run then // Вычисление ошибки с масштабированием входного сигнала (4-20 мА)
Error:= Setpoint - ScaledOutput; // расчет ошибки
Integral:= Integral + Error; // Интегральная составляющая
Derivative:= Error - PreviousError; // Дифференциальная составляющая
OutputSignal_RAW:= Kp * Error + Ki * Integral + Kd * Derivative; // Вычисление выходного сигнала
PreviousError:= Error; // Сохранение текущей ошибки для следующего шага
elsif not Run then
OutputSignal_RAW:= 0;
end_if

OutputSignal_LOW:= OutputSignal_RAW/100; // масштабирование для АО
IF OutputSignal_LOW < MinOutput then // ограничение от 0 до 1
OutputSignal_LOW:= MinOutput;
elsif OutputSignal_LOW > MaxOutput then
OutputSignal_LOW:= MaxOutput;
end_if

OutputSignal_HIGH:= (OutputSignal_RAW-100)/100; // масштабируем для АО
IF OutputSignal_HIGH < MinOutput then // ограничение от 0 до 1
OutputSignal_HIGH:= MinOutput;
elsif OutputSignal_HIGH > MaxOutput then
OutputSignal_HIGH:= MaxOutput;
end_if
// логика насосов
if AlarmFM1 and AlarmFM2 and low_inlet_press then // если нет ошибок
AlarmOut_b:= false;
AlarmOut_U:= 0;
if Run and which_pump= 0 then // стандартный режим
PumpSw (I:= true,Th:= Time_switch,Tl:= Time_switch,Q=>switch_Pump);
if switch_Pump then
FM1:= OutputSignal_LOW;
FM2:= OutputSignal_HIGH;
else
FM2:= OutputSignal_LOW;
FM1:= OutputSignal_HIGH;
end_if

elsif run and which_pump= 1 then
FM1:= OutputSignal_LOW;
FM2:= 0;
elsif run and which_pump= 2 then
FM1:= 0;
FM2:= OutputSignal_LOW;
elsif run and which_pump= 3 then
FM1:= OutputSignal_LOW;
FM2:= OutputSignal_HIGH;
elsif run and which_pump= 4 then
FM1:= OutputSignal_HIGH;
FM2:= OutputSignal_LOW;
else
FM1:= 0;
FM2:= 0;
PumpSw (I:= false);
end_if
// реакции на ошибки
elsif not AlarmFM1 and not AlarmFM2 and low_inlet_press then // авария 1 и 2 насоса
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 4;//

elsif not AlarmFM1 and low_inlet_press then // авария 1 насоса
if Run then
if which_pump= 0 or which_pump>= 2 then
FM1:= 0;
FM2:= OutputSignal_LOW;
AlarmOut_b:= true;
AlarmOut_U:= 1;//
elsif which_pump= 1 then
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 1;//
elsif which_pump= 2 then
FM1:= 0;
FM2:= OutputSignal_LOW;
AlarmOut_b:= false;
AlarmOut_U:= 0;//
end_if

elsif not run and which_pump= 2 then
FM1:= 0;
FM2:= 0;
AlarmOut_b:= false;
AlarmOut_U:= 0;//
else
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 1;//
end_if

elsif not AlarmFM2 and low_inlet_press then // авария 2 насоса
if Run then
if which_pump= 0 or which_pump>= 3 then
FM1:= OutputSignal_LOW;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 2;//
elsif which_pump= 2 then
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 2;//
elsif which_pump= 1 then
FM1:= OutputSignal_LOW;
FM2:= 0;
AlarmOut_b:= false;
AlarmOut_U:= 0;//
end_if

elsif not run and which_pump= 1 then
FM1:= 0;
FM2:= 0;
AlarmOut_b:= false;
AlarmOut_U:= 0;//
else
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 2;//
end_if

elsif not low_inlet_press then // сухой ход
FM1:= 0;
FM2:= 0;
AlarmOut_b:= true;
AlarmOut_U:= 3;//
end_if

END_FUNCTION_BLOCK

Мне кажется дешевле ничего не трогать, в смысле, идеальный вариант!

А чего хотят, чтобы при аварии одного из насосов запускался другой?
Так поставьте проводок, в смысле, там выход ПЧ можно запрограммировать(назначить функцию) на аварию!

FPavel
11.10.2024, 14:04
Не уясню, что такое "варварство"...

Для двух насосов отопления (ГВС), один из которых постоянно работает, поддерживая давления, когда-то использовал:
- два ПЧВ со своими ПИД
- ОДИН датчик давления
- САУ-У

Сейчас выпускаются специализированные приборы управления насосными группами как с использованием ПЧВ, так и без них.
ОВЕН выпускает СУНА-121/122 - посмотрите их алгоритмы, может какой-то подойдёт.

А если уж делать на ПР, то полноценно использовать и датчики сухого хода, и индивидуальные датчики-реле перепада давления (врезанные до обратных клапанов), и использовать защиты по перегрузке по току, по длительному отсутствию повышения давления при работающем насосе, учет наработки, историю ошибок, диспетчеризацию (по Modbus).

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

Посмотрите сначала готовый прибор. Датчика давления достаточно одного на 2 ПЧВ.

Биба
14.10.2024, 07:06
Мне кажется дешевле ничего не трогать, в смысле, идеальный вариант!

Согласен!


А чего хотят, чтобы при аварии одного из насосов запускался другой?
Так поставьте проводок, в смысле, там выход ПЧ можно запрограммировать(назначить функцию) на аварию!

Чтобы как в нормальных станциях - сменялись насосы, не работали одновременно оба если нет необходимости, защиту от сухого хода, защиту от аварий насоса/ПЧ.
Короче, полноценную станцию, но по цене ПР.


Сейчас выпускаются специализированные приборы управления насосными группами как с использованием ПЧВ, так и без них.
ОВЕН выпускает СУНА-121/122 - посмотрите их алгоритмы, может какой-то подойдёт.

Спасибо за наводку, посмотрю.

Сергей0308
14.10.2024, 09:12
В соседней теме подобное рассматривали, в смысле, можно посмотреть механизм ротации, включение резервного на помощь первому насосу или при аварии первого насоса и т.п.:
https://owen.ru/forum/showthread.php?t=40336