Сообщение от
Алексей Дмитриев
Прошло уже много лет, а тема до сих пор актуальна! Боролся и я в свое время с библиотечными творениями, но закончилось это написанием простого функционального блока, который устраивает в 99% случаев.
Вот код:
FUNCTION_BLOCK PID_REG
VAR_INPUT
EN:BOOL; (*Включить регулятор*)
SETP: REAL ; (*Уставка*)
FEED: REAL ; (*Обратная связь*)
MAN_IN: REAL; (*Выход в ручном режиме*)
KP: REAL ; (*Коэффициент усиления*)
KI: REAL ; (*Коэффициент усиления интегрального звена*)
KD: REAL; (*Коэффициент усиления дифференциального звена*)
MAX_V: REAL; (*Максимум выхода*)
MIN_V: REAL; (*Минимум выхода*)
RES: BOOL; (*Сброс регулятора*)
MAN: BOOL; (*Ручной режим*)
CLOCK: DINT; (*Текущее время*)
END_VAR
(*Вход CLOCK - часы, постоянно инкрементируемое двойное слово. Частота может быть любой.
Это зависит от того с какой точностью необходимо обрабатывать временные интервалы.*)
VAR_OUTPUT
END:BOOL; (*Регулятор включен*)
LMN: REAL ; (*Выход регулятора*)
END_VAR
VAR
E_N,E_N1,E_N2,U_N0,U_N1: REAL;
DELTA_T,KI_DISCR,KD_DISCR: REAL;
ST0,ST1: DINT;
END_VAR
(*Собственно код*)
IF EN THEN (*Если включено, то ПОЕХАЛИ!*)
(*Посчитаем отклонения во все моменты времени*)
E_N2:=E_N1;
E_N1:=E_N;
E_N:=SETP-FEED;
ST1:=ST0;
ST0:=CLOCK;
DELTA_T:=DINT_TO_REAL(ST0-ST1)/10.0; (*Временной интервал X Сек. Часы на входе с дискретностью X/10 Сек*)
(*А теперь с коэффициентами*)
KI_DISCR:=KI*DELTA_T;
KD_DISCR:=KD/DELTA_T;
(*Собственно - выход, то есть сумма интегрального и дифференциального звена*)
U_N0:=U_N1+KI_DISCR*E_N+KD_DISCR*(E_N-2*E_N1+E_N2);
IF KI>0 THEN
IF KP*E_N+U_N0>MAX_V THEN (*Проверка максимума*)
U_N0:=MAX_V-KP*E_N;
END_IF;
IF KP*E_N+U_N0<MIN_V THEN (*Проверка минимума*)
U_N0:=MIN_V-KP*E_N;
END_IF;
ELSE U_N0:=0;
END_IF;
IF RES=TRUE THEN (*Сброс, однако*)
U_N0:=0;
END_IF;
IF MAN=TRUE THEN (*Ручной режим*)
U_N0:=MAN_IN-KP*E_N;
END_IF;
U_N1:=U_N0;
LMN:=KP*E_N+U_N0; (*Добрались, таки до выхода*)
END:=TRUE; (*Все посчитано*)
ELSE
END:=FALSE; (*Регулятор отключен, дальше тоже ничего не выполняется*)
LMN:=0; (*Выход, на всякий случай обнулим*)
END_IF;
Пробуйте, видоизменяйте как душе угодно!