Для большинства приложений достаточно организовать не ПИД-, а ПИ-регулирование. Поэтому здесь представлен ПИ-регулятор, написанный на языке C с реализацией на целочисленной арифметике. В данном случае используется структура для хранения, как коэффициента усиления, так и интегральной составляющей, что очень удобно при портировании кода для различных приложений. Ошибка передается в качестве аргумента функции, поэтому следует соблюдать осторожность, чтобы убедиться, что вычисление ошибки, которое должно производиться вне регулятора, то есть в пользовательском коде, не вызывает переполнение.
Для борьбы с насыщением регулятора проверяется выход, и если P+I (пропорциональная и интегральная части) превышает требуемый диапазон регулирования, то новое значение интегратора не сохраняется, если все это только способствует насыщению. Это позволяет предотвратить большие выбросы при сильных шумах или при больших уставках на входе.
Этот контроллер реализован в целочисленной арифметике. Для обеспечения дробного масштаба конечный результат сдвигается вправо. Для получения желаемой точности можно менять количество бит, на которое будет осуществлен сдвиг. Для более точной настройки можно менять параметры kp и ki.
/**
* Пропорционально-интегральный (ПИ) регулятор.
*
* Этот модуль реализует простой ПИ-регулятор:
*
* u = [ kp * e + ki * sum(e) ] >> shift
*
* shift как параметр, задающий число бит, на которое
* будет сдвинут вправо результат, чтобы обеспечить необходимую точность.
*
* Предотвращение насыщения:
* - Высчитывается новое выходное значение.
* - Если оно превышает предел, и последнее изменение постоянной времени
* интегратора имеет то же направление (на увеличение или на уменьшение),
* то новое значение постоянной времени не сохраняется.
* - Иначе, это значение сохраняется.
*/
#include <stdbool.h>
#include "pi_control.h"
int pi_control (struct PIControl *p, int e)
{
bool int_ok; /* определяет, должна ли интегральная составляющая обновляться */
long new_i; /* новое значение интегральной составляющей */
long u; /* выходная величина */
/* Считаем новую интегральную составляющую и выходную величину */
new_i = p->i + e;
u = (p->kp * (long)e + p->ki * new_i) >> p->shift;
/* Проверяем на насыщение. */
int_ok = true;
/* Оно положительное? */
if (u > p->max)
{
u = p->max;
/* Тот же знак? Запрет интегрирования. */
if (e > 0)
{
int_ok = false;
}
}
/* То же самое для отрицательного значения */
else if (u < p->min)
{
u = p->min;
if (e < 0)
{
int_ok = false;
}
}
/* Если разрешено, то обновляем интегральную составляющую */
if (int_ok)
{
p->i = new_i;
}
return (int)u;
}
/**
* Инициализация ПИ-регулятора.
*
* Эта функция сбрасывает ПИ-регулятор в ноль..
*
*/
void pi_control_init (struct PIControl *p)
{
p->i = 0L;
}
/* Заголовочный файл */
#if !defined(_PI_CONTROL_H)
#define _PI_CONTROL_H
/** Структура данных ПИ-регулятора. Она содержит настройки
(коэффициент усиления, интегральная часть, а также конечный делитель),
выходные пределы, и аккумулятор интегральной части. */
struct PIControl
{
int kp; /**Коэф-т усиления*/
int ki; /** Интегральная составляющая*/
unsigned char shift; /**Сдвиг вправо*/
int max; /** Максимальное значение */
int min; /** Минимальное значение */
long i; /** Текущее значение интегральной части */
};
int pi_control (struct PIControl *p, int e);
void pi_control_init (struct PIControl *p);
#endif /* _PI_CONTROL_H */
Перевод © digitrode.ru