У меня есть код (ESP8266 с кодом Arduino) ниже, который реализует ПИД-логику для достижения и поддержания температуры 5-литрового варочного котла, используя твердотельное реле и электрический нагревательный элемент мощностью 3 кВт 220 В.Даже используя алгоритм автонастройки, kp, ki, kd генерируют очень высокий выброс (+ 5ºC выше заданного значения).
int WindowSize = 5000;
unsigned long windowStartTime;
double KettleSetpoint, KettleInput, KettleOutput;
PID _kettlePID = PID(&KettleInput, &KettleOutput, &KettleSetpoint, 1, 1, 1, DIRECT);
PID_ATune aTune(&KettleInput, &KettleOutput);
double aTuneStep = 5000, aTuneNoise = 1, aTuneStartValue = 0;
unsigned int aTuneLookBack = 20;
byte ATuneModeRemember = 2;
double kp = 2, ki = 0.5, kd = 2;
...
void KettleHeaterService::StartPID(double kp, double ki, double kd)
{
_kettlePID.SetTunings(kp, ki, kd);
_kettlePID.SetOutputLimits(0, WindowSize);
windowStartTime = millis();
_kettlePID.SetMode(AUTOMATIC);
}
void KettleHeaterService::StartAutoTune()
{
KettleOutput = aTuneStartValue;
aTune.SetNoiseBand(aTuneNoise);
aTune.SetOutputStep(aTuneStep);
aTune.SetLookbackSec((int)aTuneLookBack);
ATuneModeRemember = _kettlePID.GetMode();
}
void KettleHeaterService::Compute()
{
KettleInput = _activeStatus->Temperature;
KettleSetpoint = _activeStatus->TargetTemperature;
if (_activeStatus->PIDTuning)
{
Serial.println("tuning..");
if (aTune.Runtime() != 0)
{
_activeStatus->PIDTuning = false;
_activeStatus->BrewStarted = false;
_activeStatus->StartTime = 0;
_activeStatus->EndTime = 0;
_brewSettingsService->KP = aTune.GetKp();
_brewSettingsService->KI = aTune.GetKi();
_brewSettingsService->KD = aTune.GetKd();
_brewSettingsService->writeToFS();
_kettlePID.SetMode(ATuneModeRemember);
_kettlePID.SetTunings(_brewSettingsService->KP, _brewSettingsService->KI, _brewSettingsService->KD);
}
}
else
_kettlePID.Compute();
Serial.print("OUTPUT: ");
Serial.println(KettleOutput);
unsigned long now = millis();
if (now - windowStartTime > WindowSize)
{
windowStartTime += WindowSize;
Serial.println("time to shift the Relay Window");
}
if (KettleOutput > now - windowStartTime)
{
digitalWrite(HEATER_BUS, HIGH);
_activeStatus->PWM = 1023;
Serial.println("on");
}
else
{
digitalWrite(HEATER_BUS, LOW);
_activeStatus->PWM = 0;
Serial.println("off");
}
}
Есть ли ошибка в этой логике?Почему мой алгоритм настройки не генерирует значения kp, ki, kd правильно, чтобы избежать перерегулирования?