-=Женек=- 0 28 июля, 2019 Опубликовано 28 июля, 2019 · Жалоба Друзья, помогите с натройкой PID-регулятора. Хотя тут наверное проблема не в настройке коэффициентов, а в самом коде. Работает он в печке, которая горячо обсуждалась в соседней теме. Забегая вперед, скажу, что термопрофиль она держит прекрасно. Но есть одно но. Мощность нагревателя у меня регулируется от 1 до 100. С шагом в 1. А регулятор выдает значения кратные 10-ти, то есть при его настройках он способен выдать всего 10 значений Стал настраивать, начал, как полагается с коэффициента P. Температура смогла "угнаться" за графиком только тогда, когда я поставил коэффициент P=10. При этом никогда не было необходимости во включении печки на полную мощность - максимум 50%. Если ставить скажем 3, то картина такая Если же ставить P=10, то, повторюсь, все нормально, однако регулятор выдает значения в диапазоне от 0 до 100 с шагом 10. То есть 0,10,20,30,40... И когда идеальным значением, к примеру было бы 5 - регулятор попеременно выдает 10 и 0. В виду температурной инерции это на конечный результат не влияет, но лампы мигают. Что не так? Код (не мой) /************************************************************************/ /* AVR PID Library source file */ /* @author Gazizov A.T. [email protected] */ /************************************************************************/ #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. [email protected] */ /************************************************************************/ /** 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); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rkit 3 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба 8 hours ago, -=Женек=- said: Что не так? Ну наверно то, что вместо того, чтобы взять четкую проеверенную методику, и тупо ей следовать, вы придумали непонятно что и непонятно чем недовольны. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
-=Женек=- 0 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба 20 minutes ago, rkit said: Ну наверно то, что вместо того, чтобы взять четкую проеверенную методику, и тупо ей следовать, вы придумали непонятно что и непонятно чем недовольны. Под методикой вы понимаете алгоритм расчета выходного сигнала или настройку коэффициентов? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexRayne 7 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба вродь нормальный пид на первый взгляд. отлаживать надо. попробуйте SAMPLE_TIME поменять - может оно вносить эту кратность. но полюбому надо отладчиком смотреть что с вашими числами происходит, есть ли где кривое округление Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
-=Женек=- 0 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба Да.... если вдруг кто-то неправильно понял меня - график, что я привел, может навести кого либо (например форумца rkit) на мысль о том, что не настроен D коэффициент и имеет место статическая ошибка. Это не так. При коэффициенте p=3 -это лучшее, чего удается добиться за счет настройки остальных коэффициентов. И при p=3 проблема все равно остается - ПИД не выдает выходных значений кроме как кратных трем. Меня именно это беспокоит. 8 minutes ago, AlexRayne said: попробуйте SAMPLE_TIME поменять - может оно вносить эту кратность. Изначально у меня была ошибка в программе - вызов пид контроллера вызывался в основном цикле программы без каких либо условий, то есть работал так часто, насколько позволяло быстродействие контроллера. Я исправил ошибку - привязал вызов функции к таймеру, по которому у меня измеряется температура, то есть вызываю её тотчас после очередного измерения и строго один раз в 0.1 сек. Не изменилось ровным счетом ничего. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alexashka 0 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба А если "I" увеличить? По идее интеграл должен компенсировать расхождение с течением времени, пусть даже будут небольшие колебания вокруг уставки. Код не смотрел. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
-=Женек=- 0 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба 12 minutes ago, Alexashka said: А если "I" увеличить? По идее интеграл должен компенсировать расхождение с течением времени, пусть даже будут небольшие колебания вокруг уставки. Код не смотрел. Зря я наверное график выложил. Проблема не в нем. Манипуляции с I , если мне не изменяет память, вносили задержку в реакции системы на отклонение температуры от заданной. Что-то мне подсказывает, что умножение прмежуточных значений на коэффициент p происходит поздновато. То есть система рассчитала некое значение с точностью до единицы, а потом тупо умножила его на 10. P.S. сколько раз убеждался, что стремление сэкономить время, взяв чужой код, не приносит желаемого результата. Хотя код-то не выдран откуда-то, он написан, скажем так, в экспортном формате, готов для использования Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
-=Женек=- 0 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба Хм... если вглядеться в формулу, то получается, что на каждый 1 градус ошибки при коэффициенте р=10 система увеличивает мощность на 10 %. То есть нужно просто точнее измерять температуру. Если этому коду скармливать значения ошибки с шагом в 0.1 градус, то тогда и шаг температуры будет 1%. В принципе у меня разрешение измерения -0.25 градуса. А у меня регулятору подается значение типа int. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Дима 0 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба 14 hours ago, -=Женек=- said: Если же ставить P=10, то, повторюсь, все нормально, однако регулятор выдает значения в диапазоне от 0 до 100 с шагом 10. То есть 0,10,20,30,40... И когда идеальным значением, к примеру было бы 5 - регулятор попеременно выдает 10 и 0. В виду температурной инерции это на конечный результат не влияет, но лампы мигают. Что не так? Вы и сами поняли уже похоже, нужно разрешение увеличить, не 100 градусов, а 1000 или 10000 значений. Тогда если статическая ошибка и будет, то будет она 0.1 градусов и вы ее наверное не увидите глазами. Но шаг будет маленький, нужно чаще вызывать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
-=Женек=- 0 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба 44 minutes ago, Дима said: Вы и сами поняли уже похоже, нужно разрешение увеличить, не 100 градусов, а 1000 или 10000 значений. Тогда если статическая ошибка и будет, то будет она 0.1 градусов и вы ее наверное не увидите глазами. Но шаг будет маленький, нужно чаще вызывать. Да, действительно понял. Я любитель, без технического образования. Что такое интеграл - забыл. Что такое дифференциал - для меня это часть ходовой в автомобиле) шутка. Не надо было бояться этого ПИДа), вот и все. Если будет шаг в 2.5% мощности, то я думаю, это существенно улучшит ситуацию. Самое смешное, чтобы совсем не было мерцания от 0 до 2.5%, нужно увеличить величину тепловых потерь))) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
-=Женек=- 0 29 июля, 2019 Опубликовано 29 июля, 2019 · Жалоба Да.... вот что значит чужой код. Настроил разрешение измерения температуры - pid_out стал дробным, но все равно стал меняться с шагом 10. А цуцик вот где был зарыт double pid_Controller(int16_t setPoint, int16_t processValue) измеренная и целевая температуры выражались в целых числах. За всеми проверять нужно... 15 hours ago, rkit said: Ну наверно то, что вместо того, чтобы взять четкую проеверенную методику, и тупо ей следовать, вы придумали непонятно что и непонятно чем недовольны. Так все-таки, поясните Ваши слова? Какую методику я проигнорировал, в ней ли было дело? Или так - прочитали по диагонали и решили выпендриться? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться