Н.В. Клиначёв

Код программы PI-регулятора без интегрального насыщения

Рабочие файлы: [ПИ и ПИД без насыщения]

Данный интерактивный документ является интерактивным приложением к статье о регуляторах без интегрального насыщения (см. ссылку на рабочий файл). И все для чего этот документ был создан – это 6 пронумерованных ниже по тексту в листинге 2 строк кода. Это программный код PI-регулятора без интегрального насыщения для процессора / микроконтроллера с целочисленным АЛУ. Создать данный документ и отладить целевой код не сложно. Из инструментов нужен лишь браузер и редактор текста (Блокнот). Поясним особенности функционирования математического ядра моделирующей программы, к которому подключена библиотека с кодом пользователя.

Ниже по тексту листинг 1 – это веб-форма, в которой можно редактировать текст программного кода. В модели, представленной на чертеже 1, есть dll-блок. Как только указатель мыши выходит за границу редактора, браузер компилирует код и подключает к математическому ядру (к dll-блоку). Таким образом можно отлаживать прототип программного кода, который, после преобразования с языка JavaScript в язык Си, будет исполняться микроконтроллером.

Любая цифровая САР формирует управляющее воздействие через равные интервалы (дискреты) времени. В моделях – это шаг симуляции (параметр TimeStep). Но особенность функционирования математических ядер в том, что в зависимости от выбранного метода интегрирования, шаг симуляции может быть поделен на несколько субшагов. А если используется итерационный решатель (для решения алгебраических уравнений), то на каждом субшаге все математические блоки могут быть вызваны множество раз. Что не соответствует физическому объекту. Потому программный код делят на две последовательные части.

Согласно предложенному разработчиком математического ядра программы Jigrein протоколу, для определения dll-блока необходимо написать три функции с заданными именами и списком параметров: tune, calcStep, stepEnd. Функции calcStep и stepEnd – это и есть две последовательные части кода. Обратите внимание, как изображен на чертеже регистр задержки – основа любого дискретного интегратора (блок 1/z). Он "распилен" на две части (так же как любой другой блок с эффектом памяти). Т.е. это не один блок, а два. Они просто используются в паре. Один является источником сигнала (и вызывается первым). Другой – приёмником (вызывается в последнюю очередь). На каждом шаге симуляции, значение, которое хранит регистр задержки можно запросить сколько угодно раз. И для этого нужна функция calcStep. А вот обновить значение регистра на шаге симуляции можно лишь один раз. Для этого предназначена функция stepEnd. Когда программу переделывают для микроконтроллера. Две функции просто объединяют.

САР температуры инкубатора

Листинг 1. Программный код dll-блока (javascript)

Удалите все пронумерованные строки кода в листинге 1. Удалите блок dll. Подключите объект к выходу второго PI-регулятора и перейдите в его субуровень. Установите в новый блок dll. Добавьте блоку второй вход. Замените им сумматор дифференциатора. Напишите соответствующий код. Убедитесь в работоспособности модели. Удаляйте блоки регулятора по одному. Добавляйте код. Контролируйте работоспособность. Если ввод в форму будет заблокирован. Кликните по чертежу модели и верните курсор мыши в область редактора кода.

/* Программный код 'PI-регулятора без интегрального насыщения'.
 * В чертеже модели представлен dll-блоком (входы - массив x, выходы - y).
 */
function () {
    var GL_Q = 0 | 24;    // 14..27 // Количество разрядов в слове под дробную часть
    // Эмуляция кодирования числа с плавающей точкой в целом типе данных (32-х битное слово)
    function _IQ(x)     { return !GL_Q ? x     : 0 | (x * (1 << GL_Q)); }
    // Эмуляция умножения двух целых чисел, в которых закодированы числа с плавающей точкой
    function _IQmpy(x, y)
    { return !GL_Q ? x * y : 0 | ((x / (1 << GL_Q)) * (y / (1 << GL_Q)) * (1 << GL_Q)); }


    // #define-секция Си-программы. Параметры системы управления
    var dT = +1,                    // Период дискретизации системы управления, сек
        Kp = 0.6,                   // Коэффициент усиления P-канала PI-регулятора
        Ti = +40;                   // Постоянная  времени  I-канала PI-регулятора

    // Внутренние координаты и параметры эквивалентного PD-I-регулятора
    var zo1 = _IQ(0.0),             // Выход регистра задержки дифференциатора
        zo2 = _IQ(0.0),             // Выход регистра задержки интегратора
        Kdr = _IQ(Kp),
        Kpr = _IQ(Kp / (Ti * dT));

    function tune(mode) {
        zo1 = _IQ(0.0); zo2 = _IQ(0.0);
    }
    function calcStep(x, y, z) {
        y[0] = zo2 / (1 << GL_Q);                                               // 1
    }
    function stepEnd(x) {
        var er = _IQ(x[0]);                                                     // 2
        var dx = er - zo1;                                                      // 3
        zo2 += _IQmpy(er, Kpr) + _IQmpy(dx, Kdr);                               // 4
        zo2 = zo2 > _IQ(1.0) ? _IQ(1.0) : zo2 < _IQ(0.0) ? _IQ(0.0) : zo2;      // 5
        zo1 = er;                                                               // 6
    }
    return { tune: tune, calcStep: calcStep, stepEnd: stepEnd };
}

Листинг 2. Код PD-I-регулятора для процессора с целочисленным АЛУ

Обновите веб-страницу, чтобы листинг 1 вернулся к исходному виду. Сравните листинг 1 и листинг 2. Убедитесь в том, что по смыслу это один и тот же код. Лишь стиль написания разный. Но дело не в стиле. Код, представленный в листинге 1, после компиляции исполняется математическим сопроцессором с плавающей точкой. А код листинга 2, хоть и содержит числа с плавающей точкой, но после компиляции исполняется командами целочисленной арифметики. Скопируйте код с листинга 2 в буфер обмена. Замените им программный код dll-блока (листинг 1). Запустите модель. Убедитесь в том, что движение координат системы не изменилось.

Примечание. На сайте имеется множество документов, в которых более подробно описаны те или иные аспекты связанные с проектированием цифровых управляющих систем. В одних документах имеются подробные комментарии к аргументам функций tune, calcStep, stepEnd. В других объяснён IQ-стиль написания вычислительного кода. В третьих разъяснены причины, по которым наличие математического сопроцессора не является аргументом в пользу использования арифметики с плавающей точкой.

20.05.2017