Jump to content

    
Sign in to follow this  
-=Женек=-

PID-регулятор - не могу добиться плавности.

Recommended Posts

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

 

Мощность нагревателя  у меня регулируется от 1 до 100.  С шагом в 1.   А регулятор выдает значения кратные 10-ти, то есть при его настройках он способен выдать всего 10 значений

Стал настраивать, начал, как полагается с коэффициента P.

Температура смогла "угнаться" за графиком только тогда, когда я поставил коэффициент P=10. При этом никогда не было необходимости во включении печки на полную мощность - максимум 50%.

Если ставить скажем 3, то картина такая 

YfQeNH80.png

 

Если же ставить P=10, то, повторюсь, все нормально, однако регулятор выдает значения в диапазоне от 0 до 100 с шагом 10.

То есть 0,10,20,30,40...

И когда идеальным значением, к примеру было бы 5 - регулятор попеременно выдает 10 и 0.  В виду температурной инерции это на конечный результат не влияет, но лампы мигают.

Что не так?

 

 

Код (не мой)

/************************************************************************/
/* AVR PID Library source file                                          */
/* @author Gazizov A.T. gazizov@tpu.eu                                  */
/************************************************************************/
#include "stdint.h"
#include "pid.h"

/** Structure for storing PID data between calculations */
typedef struct PID_DATA {
  int16_t lastProcessValue;
  int32_t integralTerm;
  double kp;
  double ki;
  double kd;
  int16_t MAX_OUT;
  int16_t MIN_OUT;
} pidData_t;

struct PID_DATA pidData;

/* PID controller initialization. Should be called only once.
 *  @param kp - proportional coefficient.
 *  @param ki - integral coefficient.
 *  @param kd - differential coefficient. 
 */
void pid_Init(double kp, double ki, double kd)
{
  pidData.integralTerm     = INITIAL_INTEGRAL_TERM;
  pidData.lastProcessValue = INITIAL_PROCESS_VALUE;
  pid_setParams(kp, ki, kd);
  pid_setOutputLimits(DEFAULT_MIN_OUT, DEFAULT_MAX_OUT);
}

/* Main PID controller function. It should be called regularly, each SAMPLE_TIME sec.
 * @param setPoint - level desired at output of the control object.
 * @param processValue - level obtained from the control object.
 * @returns input to control object.
 */
double pid_Controller(int16_t setPoint, int16_t processValue)
{
  double error, p_term, d_term;
  double out;

  error = setPoint - processValue;

  pidData.integralTerm += pidData.ki * error;
  if (pidData.integralTerm > pidData.MAX_OUT) {
    pidData.integralTerm = pidData.MAX_OUT;
	out = pidData.MAX_OUT;
  } else {
	d_term = pidData.kd * (processValue - pidData.lastProcessValue);
	p_term = pidData.kp * error;
	out = (p_term + pidData.integralTerm - d_term);
	if (out > pidData.MAX_OUT) {
		out = pidData.MAX_OUT;
		} else if (out < pidData.MIN_OUT){
		out = pidData.MIN_OUT;
	}
  }
  pidData.lastProcessValue = processValue;
  
  return out;
}

/** Restricts PID controller output.
 *  @param Min - minimal allowed output value.
 *  @param Min - maximal allowed output value.
 */
void pid_setOutputLimits(int16_t Min, int16_t Max)
{
	if(Min > Max) return;
	pidData.MIN_OUT = Min;
	pidData.MAX_OUT = Max;
}

/** Set PID controller params with consideration of sampling time.
 *  @param Kp - proportional coefficient.
 *  @param Ki - integral coefficient.
 *  @param Kd - differential coefficient.
 */
void pid_setParams(double Kp, double Ki, double Kd)
{
   if (Kp<0 || Ki<0 || Kd<0) return;
   
   pidData.kp = Kp;
   
   pidData.ki = Ki * SAMPLE_TIME;
   pidData.kd = Kd / SAMPLE_TIME;
}

 

Заголовок

/************************************************************************/
/* AVR PID Library header file                                          */
/* @author Gazizov A.T. gazizov@tpu.eu                                  */
/************************************************************************/

/** Range of allowed PID output range. Needed to avoid sign/overflow problems. */
#define DEFAULT_MIN_OUT  0
#define DEFAULT_MAX_OUT  100


/** Sample time in seconds. 
 *  How often PID control function (pid_Controller) will be called. 
 *  Important setting dependent on timer implementation in your program.
 */
#define SAMPLE_TIME 0.1

/** Parameters for initializing */
#define INITIAL_INTEGRAL_TERM 0
#define INITIAL_PROCESS_VALUE 0

/** Library functions declaration */
void pid_Init(double p_factor, double i_factor, double d_factor);
void pid_setParams(double Kp, double Ki, double Kd);
void pid_setOutputLimits(int16_t Min, int16_t Max);
double pid_Controller(int16_t setPoint, int16_t processValue);

 

Share this post


Link to post
Share on other sites

 

8 hours ago, -=Женек=- said:

Что не так?

Ну наверно то, что вместо того, чтобы взять четкую проеверенную методику, и тупо ей следовать, вы придумали непонятно что и непонятно чем недовольны.

Share this post


Link to post
Share on other sites
20 minutes ago, rkit said:

 

Ну наверно то, что вместо того, чтобы взять четкую проеверенную методику, и тупо ей следовать, вы придумали непонятно что и непонятно чем недовольны.

Под методикой вы понимаете алгоритм расчета выходного сигнала или настройку коэффициентов?

Share this post


Link to post
Share on other sites

вродь нормальный пид на первый взгляд.

отлаживать надо.

попробуйте SAMPLE_TIME поменять - может оно вносить эту кратность. 

но полюбому надо отладчиком смотреть что с вашими числами происходит, есть ли где кривое округление

Share this post


Link to post
Share on other sites

Да.... если вдруг кто-то неправильно понял меня - график, что я привел, может навести кого либо (например форумца rkit) на мысль о том, что не настроен D коэффициент и имеет место статическая ошибка. Это не так. При коэффициенте p=3 -это лучшее, чего удается добиться за счет настройки остальных коэффициентов.

И при p=3 проблема все равно остается - ПИД не выдает выходных значений кроме как кратных трем. Меня именно это беспокоит.

8 minutes ago, AlexRayne said:

попробуйте SAMPLE_TIME поменять - может оно вносить эту кратность

Изначально у меня была ошибка в программе - вызов пид контроллера вызывался в основном цикле программы без каких либо условий, то есть работал так часто, насколько позволяло быстродействие контроллера. Я исправил ошибку - привязал вызов функции к таймеру, по которому у меня измеряется температура, то есть вызываю её тотчас после очередного измерения и строго один раз в 0.1 сек. Не изменилось ровным счетом ничего.

Share this post


Link to post
Share on other sites

А если "I" увеличить? По идее интеграл должен компенсировать расхождение с течением времени, пусть даже будут небольшие колебания вокруг уставки. Код не смотрел.

Share this post


Link to post
Share on other sites
12 minutes ago, Alexashka said:

А если "I" увеличить? По идее интеграл должен компенсировать расхождение с течением времени, пусть даже будут небольшие колебания вокруг уставки. Код не смотрел.

 Зря я наверное график выложил. Проблема не в нем. Манипуляции с I , если мне не изменяет память, вносили задержку в реакции системы на отклонение температуры от заданной.

Что-то мне подсказывает, что умножение прмежуточных значений на коэффициент p происходит поздновато. То есть система рассчитала некое значение с точностью до единицы, а потом тупо умножила его на 10. 

P.S. сколько раз убеждался, что стремление сэкономить время, взяв чужой код, не приносит желаемого результата. Хотя код-то не выдран откуда-то, он написан, скажем так, в экспортном формате, готов для использования

Share this post


Link to post
Share on other sites

Хм... если вглядеться в формулу, то получается, что на каждый 1 градус ошибки при коэффициенте р=10 система увеличивает мощность на 10 %. То есть нужно просто точнее измерять температуру. Если этому коду скармливать значения ошибки с шагом в 0.1 градус, то тогда и шаг температуры будет 1%. В принципе у меня разрешение измерения -0.25 градуса. А у меня регулятору подается значение типа int.

Share this post


Link to post
Share on other sites
14 hours ago, -=Женек=- said:

Если же ставить P=10, то, повторюсь, все нормально, однако регулятор выдает значения в диапазоне от 0 до 100 с шагом 10.

То есть 0,10,20,30,40...

И когда идеальным значением, к примеру было бы 5 - регулятор попеременно выдает 10 и 0.  В виду температурной инерции это на конечный результат не влияет, но лампы мигают.

Что не так?

Вы и сами поняли уже похоже, нужно разрешение увеличить, не 100 градусов, а 1000 или 10000 значений. Тогда если статическая ошибка и будет, то будет она 0.1 градусов и вы ее наверное не увидите глазами. Но шаг будет маленький, нужно чаще вызывать.

Share this post


Link to post
Share on other sites
44 minutes ago, Дима said:

Вы и сами поняли уже похоже, нужно разрешение увеличить, не 100 градусов, а 1000 или 10000 значений. Тогда если статическая ошибка и будет, то будет она 0.1 градусов и вы ее наверное не увидите глазами. Но шаг будет маленький, нужно чаще вызывать.

Да, действительно понял. Я любитель, без технического образования. Что такое интеграл - забыл. Что такое дифференциал - для меня это часть ходовой в автомобиле) шутка.

Не надо было бояться этого ПИДа), вот и все.  Если будет шаг в 2.5% мощности, то я думаю, это существенно улучшит ситуацию. Самое смешное, чтобы совсем не было мерцания от 0 до 2.5%, нужно увеличить величину тепловых потерь)))

Share this post


Link to post
Share on other sites

Да.... вот что значит чужой код. Настроил разрешение измерения температуры - pid_out  стал дробным, но все равно стал меняться с шагом 10.

 

А цуцик вот где был зарыт

double pid_Controller(int16_t setPoint, int16_t processValue)

измеренная и целевая температуры выражались в целых числах.

 

За всеми проверять нужно...

15 hours ago, rkit said:

 

Ну наверно то, что вместо того, чтобы взять четкую проеверенную методику, и тупо ей следовать, вы придумали непонятно что и непонятно чем недовольны.

Так все-таки, поясните Ваши слова?

Какую методику я проигнорировал, в ней ли было дело?

Или так - прочитали по диагонали и решили выпендриться?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this