<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE exportData>
<exportData ApplicationVersion="2.4.273-b53" ApplicationName="zWorkbench">
  <LibraryRefs/>
  <PrjItem InstanceFactoryInfo="ztools.FactoryTag.StPou" ID="14" Name="АНР-2">
    <Property text="PROGRAM ANR_2&#10;&#10;(* ================================================================= &#10;АЛГОРИТМ АНР-2: Настройка ПИД по двум периодам автоколебаний     &#10;Совместим с zWorkbench / CODESYS 3.5                            &#10;Источник: Кузищин В.Ф., Царев В.С. ТЕПЛОЭНЕРГЕТИКА, 2014, №4    &#10;================================================================= *)&#10;VAR_INPUT&#10;    // === Управление ===&#10;    bStart      : BOOL;           (* Запуск процедуры настройки *)&#10;    bReset      : BOOL;           (* Сброс алгоритма *)&#10;    bEnable     : BOOL := TRUE;   (* Разрешение работы *)&#10;    bpodstroika : BOOL := FALSE;  (* Удерживать выход после настройки *)&#10;    &#10;    (* === Сигналы системы === *)&#10;    rSetpoint   : REAL;           (* Задание u *)&#10;    rProcessVar : REAL;           (* Регулируемая величина y *)&#10;    rMuFeedback : REAL;           (* Текущее положение ИМ, % *)&#10;    &#10;    (* === Параметры объекта и ИМ === *)&#10;    rY0         : REAL := 10.0;    (* y при μ=0 в статике обязательно задать *)&#10;    rTm         : REAL := 30.0;   (* Время полного хода ИМ, сек *)&#10;    rMuMin      : REAL := 0.0;    (* Мин. выход ИМ, % *)&#10;    rMuMax      : REAL := 100.0;  (* Макс. выход ИМ, % *)&#10;    rDMu        : REAL := 30.0;   (* Приращение воздействия при переключении, % *)&#10;    &#10;    (* === Параметры расчёта === *)&#10;    rCycleTime  : REAL := 0.1;    (* Время цикла программы, сек *)&#10;    &#10;    rKf         : REAL := 8.0;    (* Коэффициент фильтра Д-составляющей *)&#10;    &#10;&#10;END_VAR&#10;&#10;VAR_OUTPUT&#10;    (* === Выход управления === *)&#10;    rControlOut : REAL;           (* Сигнал на ИМ μ *)&#10;    &#10;    (* === Рассчитанные параметры ПИД === *)&#10;    rKp         : REAL;           (* Коэффициент пропорциональности *)&#10;    rTi         : REAL;           (* Постоянная интегрирования, сек *)&#10;    rTd         : REAL;           (* Постоянная дифференцирования, сек *)&#10;    &#10;    (* === Статус === *)&#10;    bReady      : BOOL;           (* Настройка завершена *)&#10;    bBusy       : BOOL;           (* Идёт процесс настройки *)&#10;    eStatus     : BYTE;            (* 0-Idle, 1-Инициализация, 2-релейное управление, 3-Расчёты, 4-Завершён, 5-Ошибка *)&#10;    &#10;    (* === Диагностика === *)&#10;    rAy         : REAL;           (* Амплитуда y *)&#10;    rAmu        : REAL;           (* Амплитуда μ (1-я гармоника) *)&#10;    rRob        : REAL;           (* Модуль КЧХ объекта *)&#10;    rFob        : REAL;           (* Фаза КЧХ объекта, рад *)&#10;    rTn         : REAL;           (* Период автоколебаний, сек *)&#10;    rKob_calc   : REAL;           (* Рассчитанный Kob *)&#10;    rT1_calc    : REAL;           (* Рассчитанный T1 *)&#10;&#9;&#9;rN_Fixed    : REAL ;   (* Фиксированное n = T2/T1 *)&#10;END_VAR&#10;&#10;VAR&#10;    (* === Состояния алгоритма === *)&#10;    eState          : BYTE := 0;&#10;    &#10;    (* === Параметры реле === *)&#10;    rH              : REAL;&#10;    rU1, rU2        : REAL;&#10;    rMuPrev         : REAL;&#10;    bFirstSwitch    : BOOL;&#10;    rMuCurrent      : REAL;&#10;    &#10;    (* === Измерение периодов === *)&#10;    tEdgeTimer      : TON;&#10;    rTon, rToff     : REAL;&#10;    iPeriodCount    : INT := 0;&#10;    rLastEdgeTime   : REAL;&#10;    rCurrentTime    : REAL := 0.0;&#10;    bPrevAboveU2    : BOOL;&#10;    bPrevAboveU21    : BOOL;&#10;    bPrevBelowU11    : BOOL;&#10;    &#10;    (* === Интегралы (метод трапеций) для 2-го периода === *)&#10;    rS0_prev        : REAL := 0.0;   (* Пред. значение для S0 *)&#10;    rSc_prev        : REAL := 0.0;   (* Пред. значение для Sc *)&#10;    rSmu_prev       : REAL := 0.0;   (* Пред. значение для Sμ *)&#10;    rS0_acc         : REAL := 0.0;   (* Накопитель S0 *)&#10;    rSc_acc         : REAL := 0.0;   (* Накопитель Sc *)&#10;    rSmu_acc        : REAL := 0.0;   (* Накопитель Sμ *)&#10;    rEps_prev       : REAL := 0.0;   (* Пред. рассогласование *)&#10;    rMu_int_prev    : REAL := 0.0;   (* Пред. μ для интеграла *)&#10;    bCollectData    : BOOL := FALSE; (* Сбор данных активен *)&#10;    &#10;    (* === Промежуточные расчёты === *)&#10;    rError          : REAL;&#10;    rErrorSq        : REAL;&#10;    rC0             : REAL;&#10;    rAy_calc        : REAL;&#10;    rSm, rTs        : REAL;&#10;    rB1, rB2, rS1, rS2 : REAL;&#10;    rUnderRoot      : REAL;&#10;&#9;&#9;rC, rZ, rD, rQ : REAL;&#10;&#9;&#9;rN : BYTE;&#10;    rY3, rY6, rY40 : REAL;&#10;    rN_clamped : REAL;&#10;rY01, rY08 : REAL;&#10;rCycleTime_1 : REAL;&#10;     &#10;    &#10;    (* === Параметры модели === *)&#10;    rKob            : REAL := 1.0;&#10;    rT1             : REAL := 1.0;&#10;    rBeta           : REAL;&#10;    rOmega          : REAL;&#10;    rOmega_op       : REAL;&#10;    rKrs_op         : REAL;&#10;&#9;&#9;rKs_op         : REAL;&#10;    rYs, rMus       : REAL;&#10;&#9;&#9;Y, X, Z, C, Ar, Br, Rr_op, Fr_op, Fob_op  : REAL;&#10;    &#10;    (* === Итерационный поиск корня (Ньютон) === *)&#10;    iIter           : INT;&#10;    rX, rG, rGG, rDX : REAL;&#10;    rConverged      : BOOL;&#10;    rTolerance      : REAL := 0.001;&#10;    &#10;    (* === Аппроксимация α и Ti_op === *)&#10;    rAlpha          : REAL;&#10;    rTi_op          : REAL;&#10;    rYn_alpha, rYn_Ti : REAL;&#10;    rZ_beta, rC1, rC2, rC3 : REAL;&#10;    &#10;    (* === Защита === *)&#10;    tTimeout        : TON;&#10;    rSafetyLimit    : DINT := 600; (* Макс. время настройки, сек *)&#10;&#10;(* === Константы === *)&#10;&#9;&#9;PI_2&#9;&#9;&#9;: REAL := 6.28318530717958;&#10;    PI      : REAL := 3.14159265358979;&#10;    DEG2RAD : REAL := 0.0174532925199433;&#10;    RAD2DEG : REAL := 57.2957795130823;&#10;a03:REAL :=2.3107; b03:REAL :=0.08498; c03:REAL :=0.7814;&#10;a6:REAL :=0.06518; b6:REAL :=0.1425; c6:REAL :=0.01296;&#10;a40:REAL :=0.11897; b40:REAL :=0.03535; c40:REAL :=0.02705;&#10;d1:REAL :=13.24; d2:REAL :=1.369; d3:REAL :=2.369;&#10;&#10;a01:REAL :=0.5833; b01:REAL :=2.0133; c01:REAL :=0.8444;&#10;a08:REAL :=0.6570; b08:REAL :=7.052; c08:REAL :=4.328;&#10;d4:REAL :=0.1429; d5:REAL :=1.429; &#10;    (* === Оптимизация (по умолчанию) === *)&#10;    rRs_op      : REAL := 1.1;    (* Оптимальный модуль замкнутой КЧХ *)&#10;    rGs_op      : REAL := -70.0;  (* Оптимальный аргумент, град *)&#10;    rTi_op_def  : REAL := 2.0;    (* Косвенный показатель Ti_op *)&#10;&#9;&#9;rRrs_op :REAL := 0.91; // модуль комплексного числа зависит от rRs_op и rGs_op&#10;&#9;&#9;rFrs_op :REAL := -2.24; // аргумент комплексного чила зависит от rRs_op и rGs_op&#10;END_VAR&#10;(* ================================================================= &#10; ОСНОВНОЙ АЛГОРИТМ                                                 &#10; ================================================================= *)&#10;&#10;(* Обновление времени *)&#10;IF bEnable THEN&#10;    rCurrentTime := rCurrentTime + rCycleTime;&#10;END_IF;&#10;&#10;(* Таймаут безопасности *)&#10;tTimeout(IN := bBusy, PT := TIME_TO_DINT(T#1S) * rSafetyLimit);&#10;&#10;CASE eState OF&#10;    0: (* === IDLE === *)&#10;        bReady := FALSE;&#10;        bBusy := FALSE;&#10;        eStatus := 0;&#10;        rControlOut := rMuFeedback;&#10;        &#10;        IF bStart AND bEnable AND NOT tTimeout.Q THEN&#10;            eState := 1;&#10;            bBusy := TRUE;&#10;            eStatus := 1;&#10;&#9;&#9;&#9;&#9;ELSIF  bpodstroika AND bEnable THEN&#10;&#9;&#9;&#9;&#9;&#9; eState := 1;&#10;           eStatus := 1;&#10;        END_IF;&#10;        &#10;    1: (* === INITIALIZATION === *)&#10;        (* Расчёт гистерезиса: h = 0.04·|u - y0| *)&#10;        (*rH := 0.04 * ABS(rSetpoint - rY0);&#10;        //IF rH &lt; 0.5 THEN rH := 0.5; END_IF;&#10;        rU1 := rSetpoint - rH;&#10;        rU2 := rSetpoint + rH;&#10;        &#10;        (* Инициализация переменных *)&#10;        rMuPrev := rMuFeedback;&#10;        rMuCurrent := rMuFeedback;&#10;        bFirstSwitch := TRUE;&#10;        iPeriodCount := 0;&#10;        rTon := 0.0; rToff := 0.0;&#10;        rS0_acc := 0.0; rSc_acc := 0.0; rSmu_acc := 0.0;&#10;&#9;&#9;&#9;&#9;rN_Fixed:=10;&#10;        rEps_prev := rSetpoint - rProcessVar;&#10;        rMu_int_prev := rMuFeedback;&#10;        bCollectData := FALSE;&#10;        bPrevAboveU2 := FALSE;&#10;        bPrevAboveU21 := FALSE;&#10;        bPrevBelowU11 := FALSE;&#9;&#9;&#9;&#9;&#10;        &#10;        tEdgeTimer(IN := FALSE);&#10;        eState := 2;&#10;        eStatus := 2;&#10;        &#10;    2: (* === RELAY MODE &amp; MEASUREMENT === *)&#10;        (* --- Логика релейного элемента с гистерезисом (формула 6) --- *)&#10;        &#10;        rH := 0.04 * ABS(rSetpoint - rY0);&#10;        //IF rH &lt; 0.5 THEN rH := 0.5; END_IF;&#10;        rU1 := rSetpoint - rH;&#10;        rU2 := rSetpoint + rH;&#10;&#10;        IF bFirstSwitch THEN&#10;            (* Первое включение: сдвиг на 0.5·dμ *)&#10;            IF rProcessVar &lt; rSetpoint THEN&#10;                rMuCurrent := rMuPrev + 0.5 * rDMu;&#10;            ELSE&#10;                rMuCurrent := rMuPrev - 0.5 * rDMu;&#10;            END_IF;&#10;            bFirstSwitch := FALSE;&#10;        ELSE&#10;            (* Последующие переключения *)&#10;            IF rProcessVar &lt; rU1 THEN&#10;                rMuCurrent := rMuPrev + rDMu;&#10;            ELSIF rProcessVar &gt; rU2 THEN&#10;                rMuCurrent := rMuPrev - rDMu;&#10;            END_IF;&#10;            (* Зона гистерезиса: сохраняем предыдущее значение *)&#10;        END_IF;&#10;        &#10;        (* Ограничение выхода *)&#10;rMuCurrent := LIMIT (rMuMin,rMuCurrent,rMuMax);&#10;      &#10;        &#10;        (* --- Детектирование переключений для измерения Ton/Toff --- *)&#10;        (* Фронт: переход через U2 снизу вверх *)&#10;        IF (rProcessVar &gt; rU2) AND NOT bPrevAboveU2 THEN&#10;                iPeriodCount := iPeriodCount + 1;&#10;            bPrevAboveU2 := TRUE;&#10;        END_IF;&#10;        IF rProcessVar &lt; rU2 THEN bPrevAboveU2 := FALSE; END_IF;&#10;&#10;        IF iPeriodCount = 2 AND  NOT bPrevAboveU21 THEN&#10;&#9;&#9;&#9;&#9;rToff := rToff + rCycleTime;&#10;&#9;&#9;&#9;&#9;&#9;IF rProcessVar &lt;= rU1 THEN&#10;&#9;&#9;&#9;&#9;&#9;bPrevAboveU21:=TRUE;&#10;&#9;&#9;&#9;&#9;&#9;END_IF&#10;  &#9;&#9;&#9;END_IF&#10;         &#10;&#10;        (* Спад: переход через U1 сверху вниз *)&#10;&#10;        IF iPeriodCount = 2 AND  NOT bPrevBelowU11 AND bPrevAboveU21 THEN&#10;&#9;&#9;&#9;&#9;rTon := rTon + rCycleTime;&#10;&#9;&#9;&#9;&#9;&#9;IF rProcessVar &gt;= rU2  THEN&#10;&#9;&#9;&#9;&#9;&#9;bPrevBelowU11:=TRUE;&#10;&#9;&#9;&#9;&#9;&#9;END_IF&#10;  &#9;&#9;&#9;END_IF&#10;        &#10;        (* --- Интегрирование методом трапеций --- *)&#10;        &#10;        IF  iPeriodCount = 2 THEN&#10;        (* S0 = ∫ε·dt, Sc = ∫ε²·dt, Sμ = ∫μ·dt *)&#10;        rS0_acc := rS0_acc + 0.5 * (rEps_prev + rProcessVar) * rCycleTime;&#10;        rSc_acc := rSc_acc + 0.5 * (rErrorSq + rProcessVar*rProcessVar) * rCycleTime;&#10;        rSmu_acc := rSmu_acc + 0.5 * (rMu_int_prev + rMuCurrent) * rCycleTime;&#10;        END_IF&#10;        rEps_prev := rProcessVar;&#10;        rMu_int_prev := rMuCurrent;&#10;        rErrorSq := rProcessVar * rProcessVar;&#10;        (* --- Сбор данных только во ВТОРОМ периоде --- *)&#10;        IF iPeriodCount &gt;= 1 THEN&#10;            bCollectData := TRUE;&#10;        END_IF;&#10;        &#10;        (* --- Проверка завершения 2-го периода --- *)&#10;        IF iPeriodCount &gt; 2 THEN&#10;            rTn := rTon + rToff;&#10;                eState := 3;&#10;                eStatus := 3;&#10;        END_IF;&#10;        &#10;        (* Таймаут *)&#10;        IF tTimeout.Q THEN&#10;            eState := 9;&#10;            eStatus := 5;&#10;        END_IF;&#10;        &#10;        rMuPrev := rMuCurrent;&#10;        rControlOut := rMuCurrent;&#10;&#9;&#9;&#9;&#10;        &#10;    3: (* === CALCULATE PARAMETERS === *)&#10;        (* --- 1. Амплитуда Ay (формула 7) --- *)&#10;        IF rTn &gt; 0.0 THEN&#10;            rC0 := rS0_acc / rTn;&#10;            rUnderRoot := 2.0 * (rSc_acc / rTn - rC0 * rC0);&#10;            IF rUnderRoot &gt; 0.0 THEN&#10;                rAy := SQRT(rUnderRoot);&#10;            ELSE&#10;                rAy := 0.001;&#10;            END_IF;&#10;            IF rAy &lt; 0.001 THEN rAy := 0.001; END_IF;&#10;        ELSE&#10;            rAy := 0.001;&#10;        END_IF;&#10;        &#10;        (* --- 2. Амплитуда Aμ (формула 8, ИМ постоянной скорости) --- *)&#10;        rSm := 100.0 / rTm;          (* Скорость ИМ, %/с *)&#10;        rTs := rDMu / rSm;           (* Время фронта, с *)&#10;        rB1 := (PI * rTs) / rTn;&#10;        rB2 := (PI * rTon) / rTn;&#10;        &#10;        IF ABS(rB1) &gt; 0.001 THEN rS1 := SIN(rB1) / rB1; ELSE rS1 := 1.0; END_IF;&#10;        IF ABS(rB2) &gt; 0.001 THEN rS2 := SIN(rB2) / rB2; ELSE rS2 := 1.0; END_IF;&#10;        &#10;        rAmu := 2.0 * rDMu * rS1 * rS2 * (rTon / rTn);&#10;        IF rAmu &lt; 0.001 THEN rAmu := 0.001; END_IF;&#10;        &#10;        (* --- 3. Модуль КЧХ объекта (формула 9) --- *)&#10;&#9;&#9;&#9;&#10;        rRob := rAy / rAmu;&#10;        IF rRob &lt; 0.001 THEN rRob := 0.001; END_IF;&#10;        &#10;        (* --- 4. Фаза КЧХ объекта (формулы 10-12) --- *)&#10;        rFob := -PI; (* Базовый сдвиг *)&#10;        &#10;        (* Поправка на гистерезис *)&#10;        IF rAy &gt; (2*rH) THEN&#10;            rFob := rFob - ASIN(2.0 * rH / rAy);&#10;        END_IF;&#10;        &#10;        (* Поправка на скорость ИМ *)&#10;        IF rTs &gt; 0.0 THEN&#10;            rFob := rFob - PI * rTs / rTn;&#10;        END_IF;&#10;        &#10;        (* Поправка на асимметрию Ton ≠ Toff *)&#10; &#9;&#9;&#9;&#10;        &#9;&#9;rFob := rFob - PI_2 * ((rTon/rTn)-0.5)* ((rTon/rTn)-0.5);&#10;       &#10;        (* --- 5. Статический коэффициент Kob --- *)&#10;        rYs := rSetpoint + rC0;&#10;        rMus := rSmu_acc / rTn;&#10;&#9;&#9;&#9;&#9;&#10;        IF ABS(rMus - rMuFeedback) &gt; 0.001 THEN&#10;            rKob := ABS(rYs - rY0) / ABS(rMus);&#10;        ELSE&#10;            rKob := 1.0;&#10;        END_IF;&#10;        IF rKob &lt; 0.001 THEN rKob := 0.001; END_IF;&#10;        rKob_calc := rKob;&#10;        &#10;        (* --- 6. Безразмерная частота Ω (уравнение модулей) --- *)&#10;      &#10;        rC :=(rKob / rRob)*(rKob / rRob);&#10;&#10;        (* --- 7. Параметр β (уравнение аргументов) --- *)&#10;&#10;     &#10;REPEAT&#10;&#9;&#9;&#9;&#10;&#9;&#9;&#9;  rZ := rN_Fixed * rN_Fixed;&#10;        rD := ((1 + rZ)*(1 + rZ))- (4*rZ*(1-rC));&#10;        rQ := ((SQRT(rD)-1)/(2*rZ))-0.5;&#10;        rOmega := SQRT(ABS(rQ));&#10;        rBeta := ((-rFob - ATAN(rOmega) - ATAN(rOmega * rN))/rOmega)/100;&#10;IF rBeta &lt; 0.05 THEN&#10;&#9;&#9;&#9;&#9;rN_Fixed:=rN_Fixed+1;&#10;END_IF&#10;IF rBeta &gt; 1 THEN&#10;&#9;&#9;&#9;&#9;rN_Fixed:=rN_Fixed-1;&#10;END_IF&#10; &#9;&#9;&#9;&#9;IF tTimeout.Q THEN&#10;            eState := 9;&#10;            eStatus := 5;&#10;        END_IF;&#10;UNTIL (rBeta&gt;=0.05) AND (rBeta&lt;=1) &#10;END_REPEAT;&#10;&#10;&#9;&#9;&#9;&#9;rOmega := SQRT(ABS(rQ));&#10;        rBeta := ((-rFob - ATAN(rOmega) - ATAN(rOmega * rN))/rOmega)/100;        &#10;        (* --- 8. Постоянная времени T1 --- *)&#10;        rT1 := rOmega * (rTn / PI_2);&#10;        IF rT1 &lt; 0.1 THEN rT1 := 0.1; END_IF;&#10;        rT1_calc := rT1;&#10;        &#10;        (* --- 9. Расчёт α = Td/Ti (формула 19) --- *)&#10;        (* Аппроксимация для n=3,6,40 с интерполяцией *)&#10;        rYn_alpha:=b03+c03/(rN_Fixed+a03);&#10;      &#9;rAlpha:=(b40+(c40/(rBeta+a40)))*(d3-rYn_alpha*d1)-(b6+(c6/(rBeta+a6)))*(d2-rYn_alpha*d1);&#10;        &#10;      &#10;        &#10;        (* --- 10. Расчёт Ti_op (формула 20) --- *)&#10;&#9;&#9;&#9;&#9;rZ_beta:= d4+d5*(rBeta-0.2);&#10;&#9;&#9;&#9;&#9;rY01:= b01-c01/((1/rN_Fixed)+a01);&#10;&#9;&#9;&#9;&#9;rY08:= b08-c08/((1/rN_Fixed)+a08);&#10;       &#9;&#9;&#9;&#9;rYn_Ti:= rY01+rZ_beta*(rY08-rY01);&#10; &#9;&#9;&#9;&#9;(* --- 10.1 Расчёт оптимального вектора КХЧ*)&#10;&#9;&#9;&#9;&#9;C:= rYn_Ti/PI_2;&#10;&#9;&#9;&#9;&#9;Z:= rAlpha*rKf/C;&#10;&#9;&#9;&#9;&#9;X:= Z*Z;&#10;&#9;&#9;&#9;&#9;Y:=(X+1)*(X+1)*rKf;&#10;&#9;&#9;&#9;&#9;Ar:= 1+(2*X/Y);&#10;&#9;&#9;&#9;&#9;Br:= (1-X)*(Z/Y)-C;&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Rr_op:= SQRT((Ar*Ar)+(Br*Br));&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Fr_op:= ATAN(Br/Ar);&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Fob_op:= rFrs_op - Fr_op;&#10;rX:=0.2;&#10;REPEAT&#10;rG:= rBeta*rX + ATAN(rX) + ATAN(rX*rN_Fixed) + Fob_op;&#10;rGG:= rBeta + (1/(rX*rX+1)) + (rN_Fixed/(rN_Fixed*rN_Fixed*rX*rX+1));&#10;IF (rG/rGG)&gt;0.01 THEN&#10;rX:= rX - (rG/rGG);&#10;END_IF&#10; &#9;&#9;&#9;&#9;IF tTimeout.Q THEN&#10;            eState := 9;&#10;            eStatus := 5;&#10;        END_IF;&#10;UNTIL(rG/rGG)&lt;0.01&#10;END_REPEAT;&#10;rOmega_op:= rX;&#10;rKs_op:= Rrs_op/(Rr_op*SQRT((rOmega_op*rOmega_op+1)*(rOmega_op*rOmega_op*rN_Fixed*rN_Fixed+1)));&#10;        &#10;        (* --- 12. Параметры ПИД (формула 18) --- *)&#10;        rKp := rKs_op/rKob;&#10;        rTi := (rT1*(PI_2/rOmega_op))/rYn_Ti;&#10;        rTd := rTi * rAlpha;&#10;        &#10;        (* Ограничения параметров &#10;        IF rKp &lt; 0.01 THEN rKp := 0.01; END_IF;&#10;        IF rKp &gt; 1000.0 THEN rKp := 1000.0; END_IF;&#10;        IF rTi &lt; 0.1 THEN rTi := 0.1; END_IF;&#10;        IF rTi &gt; 3600.0 THEN rTi := 3600.0; END_IF;&#10;        IF rTd &lt; 0.0 THEN rTd := 0.0; END_IF;&#10;        IF rTd &gt; rTi THEN rTd := rTi * 0.5; END_IF;*)&#10;        &#10;        eState := 4;&#10;        eStatus := 4;&#10;        &#10;    4: (* === DONE === *)&#10;        bReady := TRUE;&#10;        bBusy := FALSE;&#10;        eStatus := 4;&#10;        &#10;        IF bReset THEN&#10;            eState := 0;&#10;            bReady := FALSE;&#10;        END_IF;&#10;        &#10;    9: (* === ERROR === *)&#10;        bBusy := FALSE;&#10;        eStatus := 5;&#10;        rControlOut := rMuMin; (* Безопасное состояние *)&#10;        &#10;        IF bReset THEN&#10;            eState := 0;&#10;        END_IF;&#10;END_CASE;&#10;&#10;(* ================================================================= *)&#10;(* ВЫХОДНОЙ СИГНАЛ                                                   *)&#10;(* ================================================================= *)&#10;IF eState &lt; 4 THEN&#10;    rControlOut := rMuCurrent;&#10;ELSE&#10;rControlOut :=0;&#10;END_IF;&#10;&#10;(* Сброс по внешнему сигналу *)&#10;IF bReset THEN&#10;    rS0_acc := 0.0; rSc_acc := 0.0; rSmu_acc := 0.0;&#10;    iPeriodCount := 0;&#10;    tEdgeTimer(IN := FALSE);&#10;END_IF;&#10;END_PROGRAM"/>
  </PrjItem>
</exportData>
