September 8, 2016

Пропорционально-интегрально-дифференцирующий

С параметрами ПИД-регулятора можно играться как с кошкой — до бесконечности: пока в колебательный процесс не впадет или не надоест.

Несмотря на тонны матана, прячущиеся за тройкой входных параметров, около 90% регуляторов в мире основано на ПИД (гугл, википедия, нормальное распределение). Именно благодаря простому интерфейсу, скрывающему интегралы-дифуры, использовать ПИД-регулятор невероятно просто, главное правильно отстроить и не умереть от скуки.

TcControllerToolbox.lib — это основная профессиональная библиотека TwinCAT для работы с регуляторами, генераторами и прочими алгоритмами автоматизации. Там много разных штук, но мы посмотрим на ПИД-регуляторы, как самые распространенные и востребованные.


PLC Controller Toolbox


В прайсе эта библиотека обозначена артикулом TF4100. Это для TwinCAT 3. Если вам нужно модернизировать старую систему на TwinCAT 2, ищите TS4100. Библиотека платная, но построена профессионально — с учетом всего того, что просто необходимо учитывать.
Например: все ФБ библиотеки контролируют циклы и тайминги программных циклов. В случае повторного вызова ФБ за один и тот же цикл или если будет пропуск цикла — ФБ адекватно обработает эту ситуацию. Даже если будет пропущен не один цикл или не один раз.

Кроме непосредственно регулирования, блоки ПИД-регулятора умеют дополнительные опции.

FB_CTRL_PI
FB_CTRL_PID
  • Контроль интегрального насыщения, верхний и нижний пределы.
  • Ручная уставка задания в обход автоматической: можно вмешаться в работу регулятора.
  • Ручное отключение интегральной составляющей.
  • Жесткий контроль циклов ПЛК-задачи и таймингов.

FB_CTRL_PID_EXT
  • Зона нечувствительности для входного значения. При нахождении в ней значение выхода регулятора постоянно.
  • Зона нечувствительности для нулевой величины выхода.
  • Окно для отключения интегральной составляющей (она постоянна или равна нулю).
  • Окно для уменьшения масштаба интегральной составляющей.

FB_CTRL_PID_SPLITRANGE
  • Аналогично FB_CTRL_PID, но можно задать разные наборы коэффициентов "p-i-d" для охлаждения (температура ниже нуля) и для нагрева (температура выше нуля).
  • Имеет два различных выхода, но активен только один. В зависимости от величины выхода — больше нуля или меньше нуля, он запускает нагрев или охлаждение, обнуляя значение противоположного выхода. Кусок кода, для разнообразия:
fOut := fY;

IF fOut > 0.0 THEN
    fOutPos := fOut;
    fOutNeg := 0.0;
ELSE
    fOutNeg := fOut;
    fOutPos := 0.0;
END_IF

FB_CTRL_PID_EXT_SPLITRANGE
  • Всё и сразу: FB_CTRL_PID + _EXT + _SPLITRANGE.


Простой ПИД-регулятор


К тому же бесплатный. Можно было бы перевести дословно — "примитивный", но он работает и это — самое главное.

В бесплатной библиотеке TcUtilities.lib, есть встроенный функциональный блок FB_BasicPID, который умеет три параметра и — все. Больше он ничего не умеет (плюс демпфирование диф.-составляющей Td, но это у разработчика случайно получилось).

Главное отличие от профессиональной библиотеки — это:

FB_BasicPID
  • нет контроля интегрального насыщения;
  • нет контроля повторного или пропущенного вызова за цикл. Вызывайте строго один раз за цикл — иначе пожалеете.

С циклом более менее понятно, а вот отсутствие контроля за интегральным насыщением (integral windup, reset windup, integral saturation) может сыграть злую шутку. Мы сейчас попробуем поиграться с этим эффектом, и заодно убедимся, что функция регулятора действительно примитивная.

Да собственно уже играемся — длинная портянка графика справа показывает, как мы сначала нагрели нечто до 27 градусов, а затем пытаемся охладить, но что-то никак не получается...
Зеленый — задание-уставка.
Синий — выход ПИД-регулятора.
Красный — актуальное, текущее значение на выходе исполнительного механизма.
... А все потому, что не хватает возможности исполнительного механизма — он не справляется, а ПИД-регулятор все топит и топит педальку тормоза-охлаждения. И график ползет вниз...

Чтобы хоть как-то исправить ситуацию, мы попробуем ограничить выход регулятора в соответствии с возможностями нашего исполнительного механизма. Предположим, что он может нагреть до 60 и охладить до 18 условных градусов, условного цельсия:

PID(
    SetpointValue := TargetValue,
    ActualValue   := ActualValue,
    Kp := kp,
    Ti := ti,
    Tv := tv,
    Td := td,
    MaxCtrlOutput := Model.LimitHi,
    MinCtrlOutput := Model.LimitLow,
    CtrlOutput    => SetpointValue);

IF SetpointValue < 18 THEN
    SetpointValue := 18;
END_IF

IF SetpointValue > 60 THEN
    SetpointValue := 60;
END_IF

Делаем мы это не из-за того, что не понимаем процессы которые происходят в регуляторы, а просто по причине недоступности внутренностей функционального блока ПИД-регулятора. Ну, не можем мы их исправить. Зато, как обычно, можно написать свой регулятор.

Пока же оставим регулятор как есть, и в итоге получим как на картинке ниже — задание изменилось и кажется, что регулятор чего-то ждет... На самом деле интегральная ошибка убежала далеко вверх (накопилась) и в данный момент стремительно падает, уменьшаясь и пытаясь достичь заданного. И это я еще ждал недолго, за сутки она бы убежала на столько далеко...



Попробуем зайти с другой стороны и заморозим накопление ошибки (интегральную часть). Для этого перепишем часть регулятора:

// расчет интегральной части
IF is_Ipart THEN
    IF (maxLimReached AND (e >= 0.0)) OR (minLimReached AND (e <= 0.0)) THEN
        yi := yi1;                    // замораживаем интегральную часть
    ELSE
        yi := yi1 + di * (e + e1);    // интегрируем
    END_IF
ELSE
    yi := 0.0;
END_IF;

[...]

y := yp + yi + yd;    // суммируем П-И-Д части для расчета выхода регулятора

// проверяем выход на ограничения
IF y < MinCtrlOutput THEN
    y := MinCtrlOutput;
    minLimReached := TRUE;
    maxLimReached := FALSE;
ELSIF y > MaxCtrlOutput THEN
    y := MaxCtrlOutput;
    minLimReached := FALSE;
    maxLimReached := TRUE;
ELSE
    minLimReached := maxLimReached := FALSE;
END_IF

CtrlOutput := y;      // формируем выход функционального блока


Проверяем:



Модель процесса


Это абстрактная модель "какого-то" объекта, имитирующая "какой-то" слегка нелинейный процесс. Чтобы придать модели линейность — уберите в расчете переменной delta часть под квадратным корнем (вместе с самим корнем SQRT) и оставьте только Grow и CycleTime.

PROGRAM Model
VAR_INPUT
    Run       : BOOL;
    Setpoint  : LREAL;
    Grow      : LREAL  := 0.1;    // градусы за секунду
    CycleTime : LREAL  := 0.01;   // секунды
    LimitHi   : LREAL  := 70;
    LimitLow  : LREAL  := 18;
END_VAR
VAR_OUTPUT
    Actual : LREAL;
END_VAR
VAR
    delta  : LREAL;
END_VAR

[...]

IF Setpoint > LimitHi THEN
    Setpoint := LimitHi;
END_IF

IF Setpoint < LimitLow THEN
    Setpoint := LimitLow;
END_IF
 
delta := Grow * CycleTime * SQRT(ABS(Actual * Actual - Setpoint * Setpoint));

IF Actual > Setpoint THEN
    Actual := Actual - delta;
ELSE
    Actual := Actual + delta;
END_IF

Если у вас есть модель получше — присылайте почтой, комментариями и пр.


Про диф.-составляющие


Чаще всего используется ПИ-регулятор. Дальше можете не читать.

Диф. составляющая, предсказывая будущее, тянет регулятора назад, "прижимая" выход и не давая ему вылезти сильно высоко (overshoot). Все эти штуки с предсказаниями могут выйти боком, если плохо понимать процесс, поэтому обычно Д-составляющая попросту не используется: отключают, приравнивая нулю.

Чтобы включить ПИД-регулятор в FB_BasicPID необходимо выставить оба диф. коэффициента в значения отличные от нуля. Причем основным диф. параметром является Tv (он расположен в числителе). Td — это время демпфирования и находится в знаменателе диф. составляющей. Его значение можно выставить равным единице и тогда останется только основная Tсоставляющая диф. компоненты ПИД-регулятора.

4 comments

  1. Hello! I have followed your blog for a long time and now when I was googling for FB_BasicPID guides I found this article.

    Do you have a PID model with that intergral anti-windup? I am currently working with BasicPID and it's not working very well because of that integral problem. You listed that code (starting with "// calculation of the integral part of ") but I can't find any more information. Could you provide it or should I create it on my own?

    Ps. The site is extremely great and it's easy enough to read with Google Translate.

    Greetings from Finland!

    ReplyDelete
    Replies
    1. Hello Jusu,

      If you have TwinCAT 2 installed on your laptop, just open C:\TwinCAT\Plc\Lib\TcUtilities.lib in the PLCControl. You can find FB_BasicPID somewhere in POUs/PID-Controller. After you find FB_BasicPID, just extends it with integral-anti-windup-control part.

      It is a bad idea to install TC2 over TwinCAT 3. If you work with TC3 on your laptop, just install TwinCAT 2 on another machine or use a virtual machine.

      Delete
    2. Thank you very much for you fast answer! I thought that all Beckhoff libraries are protected, but I forgot that TwinCAT 2 libraries were possible to be opened.

      I didn't install TwinCAT 2 as it is possible to open the library in TwinCAT 3, and it is also incuded in TwinCAT 3 package. Just create a new blank project, right-click PLC, select "Add existing item.." and select TcUtilities.lib file from "C:\TwinCAT\3.1\Components\Plc\Converter\Lib\TcUtilities.lib". Then the TwinCAT 3 converts the library and you can browse it.

      That integral fix fixed my problem, so thank you very much for this. I'll be following your blog from now on, as before. Have a nice week!

      Delete
  2. Hello,
    Is it possible to sent me FB_BasicPID function block with additional parameters for Min and Max output value from PID regulator. Please send me on my mail ales.pantar@gmail.com

    TNX very much

    Aleš Pantar
    SLOVENIA

    ReplyDelete

Note: Only a member of this blog may post a comment.