Управление отоплением 0-10в / ПИД регулятор

ПИД регулятор идея и код не мой, взят от сюда и не много доработан.


var Pid = function(opts) {
 opts = opts || {};
 this._target = opts.target || 0;
 this._kp = opts.kp || 0;
 this._ki = opts.ki || 0;
 this._kd = opts.kd || 0;
 this._outputMin = opts.outputMin || 0;
 this._outputMax = opts.outputMax === undefined ? 1 : opts.outputMax;
 this._lastTime = null;
 this._intervalId = null;
};

Pid.prototype.clip = function(x, min, max) {
  if (x < min){
    return min;
  } else if (x > max) {
    return max;
  } else {
    return x;
  }
};

Pid.prototype._clearErrors = function() {
 this._sumError = 0;
 this._lastError = 0;
 this._lastTime = null;
};

Pid.prototype.setup = function(opts) {
 this._target = opts.target === undefined ? this._target : opts.target;
 this._kp = opts.kp === undefined ? this._kp : opts.kp;
 this._ki = opts.ki === undefined ? this._ki : opts.ki;
 this._kd = opts.kd === undefined ? this._kd : opts.kd;
 this._outputMin =
  opts.outputMin === undefined ? this._outputMin : opts.outputMin;
 this._outputMax =
  opts.outputMax === undefined ? this._outputMax : opts.outputMax;
 this._clearErrors();
};

Pid.prototype.tune = function(opts) {
 this._kp += opts.kp || 0;
 this._ki += opts.ki || 0;
 this._kd += opts.kd || 0;
 this._clearErrors();
};

Pid.prototype.update = function(input) {
 //console.log("update input="+input);
 var date = new Date();
 var dt = date.getTime() - this._lastTime;
 var error = this._target - input;
 var dError = 0;
 var integralNormalized = 0;
 var differential = 0;

 if (this._lastTime) {
  dError = error - this._lastError;
  this._sumError += error;
  integralNormalized = this._ki * this._sumError * dt;
  differential = (this._kd * dError) / dt;
  integralNormalized = this.clip(
   integralNormalized,
   this._outputMin,
   this._outputMax
  );

 } else {
  this._clearErrors();
 }

 var output = this._kp * error + integralNormalized - differential;
 //console.log("output" + output);

 output = this.clip(output, this._outputMin, this._outputMax);
 //console.log("output clip" + output);
 this._lastError = error;
 var date = new Date();
 this._lastTime = date.getTime();
 return output;
};

Pid.prototype.run = function(repeat, interval) {
 if (!this._intervalID) {
  this._intervalID = setInterval(repeat, interval * 1000);
  this._clearErrors();
 }
};

Pid.prototype.stop = function() {
 if (this._intervalID) {
  clearInterval(this._intervalID);
 }
 this._intervalID = null;
};

var myControl = new Pid({
 target: 23, // требуемая величина выходного значения
 kp: 3, // пропорциональная составляющая
 ki: 0.9, // интегральная составляющая
 kd: 0.1, // дифференциальная составляющая
 outputMin: 0, // минимальное значение выхода
 outputMax: 10 // максимальное значение выхода
});


myControl.run(function() {
 var input = 23;                                      //Входное значение var input = dev["abc"]["def"];
 var output = myControl.update(input); //Выходное значение
                                                             // Выходное значение на dev["abc"]["def"] = output;
 log(output);
}, 0.05);                                              //Время запуска ПИД-регулятора каждые 50 мс 
/*Отопление это инертный процесс имеющий большое время реакции, поэтому время можно увеличить*/
3 лайка

Сами уже протестировали, удаётся держать температуру близко к заданной? В каком диапазоне гуляет? Тема прикольная, надо присмотреться. Спасибо :blush:

Отформатировал код для легкости восприятия

Очень актуальная тема - управление климатом с помощью Модуль аналогового вывода 0-10В WB-MAO4 и трехходового моторизированного клапана.

В этой теме есть всего 2 кода скриптов представленных читателями, но замечены не точности:

  1. [Starck] предлагает код как уже испытанный с погрешностью пол градуса, а через некоторое время пишет что заработало. Не понятная ситуация с отправленным кодом. Что же заработало потом если оно уже работало в момент отправки кода.
  2. [BlackBox] отправил код и исчез, код остался без комментариев.

Как известно существуют несколько видов алгоритмов регулирования: П, ПИ, ПИД. Каждый отличается скоростью достижения заданной цели. Например ПИД быстрее достигнет заданной температуры чем ПИ регулирование и также ПИ быстрее чем П.

Конечно желательно использовать ПИД регулирование. Хотелось бы использовать уже испытанный алгоритм регулирования. Если кому не жалко поделитесь пож. кодом

1 лайк

Кто-нибудь отзовется помощь?

Node-Red + готовые модули ПИД в нём.
Схема рабочая. Проверял у себя в прошлом году
когда делал систему подмеса твердотопливного котла
нагруженного на тепловой аккумулятор.

я только включаюсь в эту игру. тоже буду делиться своими наработками.

Мне так и не удалось установить Node-Red.
Поэтому нужен другой рабочий код.

Речь скорее всего шла про физическое подключение питания приводов 0-10V (24VAC).
А код как работал, так и работает, просто он раньше обслуживал лишь два клапана, а для трех одновременно надо было корректно подключать землю.
Если нет иного алгоритма, то можете взять мой на вооружение. Может не идеальный, но вполне боевой. Были мысли его усовершенствовать, но руки не доходят. Много работы.

Разберитесь со строчками 0-202 в действующем скрипте:
https://yadi.sk/d/ZdLUKcQJKlZGnw

Я для трех контуров вызываю через плавающий интервал времени функцию корректировки MOD от 0-10В. Время и величина корректировки зависят от величины изменения температуры за ед времени (сравнение идет с предыдущими сохраненными показателями темп). По мере приближения к уставке(выставленная температура в моих вирт контролах) коррекция идет плавнее, дабы не проскочить настроенную температуру. Мысли были дальше вычислять скорость изменения температуры, пересекать уставку вверх - вниз, постепенно уменьшая дельту изменения 0-10В (по принципу затухающего колебания волны)

1 лайк

Мало описания

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

1 лайк

Кто-нибудь пробовал этот алгоритм?
Я на днях запустил, код работоспособный, но в полезности я пока сомневаюсь. Пришлось сделать виртуальное устройство для подбора коэффициентов ПИД регулятора. Начитался кучу методов подбора коэффициентов ПИД регулятора. Но пока не удается подобрать нужные коэффициенты и достичь стабильности в регулировании 0-10В. Или в коде есть ошибки или не подобрал нужные коэффициенты.
Никто не занимался подбором коэффициентов для отопления?

В чем заключается стабильность регулирования на мой взгляд?
Это после того как комнатная температура достигла заданной регулирование по 0-10В перестает меняться. На данный момент я достиг показаний когда это значение меняется на единицы. Но это плохо, так как шаговому двигателю от этого не очень хорошо, выйдет из строя раньше времени.

Может проблема в виртуальном устройстве. Как его создали?

defineVirtualDevice(“HOME_Temperature”, {
title: “Home temperature”,
cells: {
“kp1” : {
type : “range”,
value : 4,
min: 0,
max : 100,
},
“ki1” : {
type : “range”,
value : 1,
min: 0,
max : 1000,
},
“kd1” : {
type : “range”,
value : 1,
min: 0,
max : 1000,
},
“Set temp Hoz” : {
type : “range”,
value : 20,
min: 15,
max : 30,
},
“Room_temperature” : {
type : “range”,
value : 19,
min: 15,
max : 30,
},
“Upravlenie”: {
type : “range”,
value : 0,
min: 0,
max : 10000,
},
}
});

// Виртуальное устройство для теста
defineVirtualDevice(“DevTest”, {
title: “Test”,
cells: {
enabled: {
type: “range”,
value: 27,
max: 34,
min: 26
},
log: {
type: “text”,
value: false,
max: 100
},
kp1: {
type: “range”,
value: 2,
min: 0,
max: 100,

},
}

});
// Начало кода PID регулятора
var Pid = function(opts) { //Конструктор объектов
opts = opts || {};
this._target = opts.target //|| 0;
this._kp = opts.kp || 0;
this._ki = opts.ki || 0;
this._kd = opts.kd || 0;
this._outputMin = opts.outputMin || 0;
this._outputMax = opts.outputMax === undefined ? 1 : opts.outputMax;
this._lastTime = null;
this._intervalId = null;
};

Pid.prototype.clip = function(x, min, max) { //Функция ограничения выходных значений регулирующего устройства
if (x < min){
return min;
} else if (x > max) {
return max;
} else {
return x;
}
};

Pid.prototype._clearErrors = function() { //Функция очистки накопленной ошибки PID регулятора
this._sumError = 0;
this._lastError = 0;
this._lastTime = null;
};

Pid.prototype.setup = function(opts) {
this._target = opts.target === undefined ? this._target : opts.target;
this._kp = opts.kp === undefined ? this._kp : opts.kp;
this._ki = opts.ki === undefined ? this._ki : opts.ki;
this._kd = opts.kd === undefined ? this._kd : opts.kd;
this._outputMin =
opts.outputMin === undefined ? this._outputMin : opts.outputMin;
this._outputMax =
opts.outputMax === undefined ? this._outputMax : opts.outputMax;
this._clearErrors();
};

Pid.prototype.tune = function(opts) {
this._kp += opts.kp || 0;
this._ki += opts.ki || 0;
this._kd += opts.kd || 0;
this._clearErrors();
};

Pid.prototype.update = function(input) { //Функция PID регулятора
var date = new Date();
var dt = date.getTime() - this._lastTime;
var error = this._target - input;
var dError = 0;
var integralNormalized = 0;
var differential = 0;

if (this._lastTime) {
dError = error - this._lastError;
this._sumError += error;
integralNormalized = this._ki * this._sumError * dt;
differential = (this._kd * dError) / dt;
integralNormalized = this.clip(
integralNormalized,
this._outputMin,
this._outputMax
);

} else {
this._clearErrors();
}

var output = this._kp * error + integralNormalized - differential;

output = this.clip(output, this._outputMin, this._outputMax);
this._lastError = error;
var date = new Date();
this._lastTime = date.getTime();
return output;
};

Pid.prototype.run = function(repeat, interval) {
if (!this._intervalID) {
this._intervalID = setInterval(repeat, interval * 1000);
this._clearErrors();
}
};

Pid.prototype.stop = function() {
if (this._intervalID) {
clearInterval(this._intervalID);
}
this._intervalID = null;
};
//Создаем объект с нужными параметрами PID регулятора

var myControl = new Pid({
target: 20, // требуемая величина выходного значения
kp: 0.5, // пропорциональная составляющая
ki: 5, // интегральная составляющая
kd: 0.1, // дифференциальная составляющая
outputMin: 0, // минимальное значение выхода
outputMax: 10 // максимальное значение выхода
});

myControl.run(function() {

var input = dev[“DevTest”][“enabled”]; //Входное значение от виртуального устройства
var output = myControl.update(input); //Выходное значение
dev[“DevTest”][“log”] = String(output); //Выходное значение передаем в виртуальное устройство
myControl.kp = dev[“DevTest/kp1”]; //Пример для подбора параметров PID
myControl.setup(myControl); //Пример для подбора параметров PID
}, 2); //Интервал запуска ПИД-регулятора каждые 200 мс

4 лайка

Привет, немного подниму тему, тут смотрел докумнтацию к опциональному контроллеру к своему смесительному узлу valtec и увидел интересную идею: за счет ШИМ управляют обычной 24в термоголовкой, без 0-10v. По документации не понятно - там медленный ШИМ (10ки секунд или минуты период) или быстрый.
Мне видится быстрый (на уровне кГц) будет вполне работоспособен - нагрев нагревателя в термоголовке будет пропорционален. Получается - берем wb-led и можно подключать 4 головки и точно регулировать. Никто еще не реализовывал? Или может видите принципиальные подводные камни?

Как отрицательные моменты это:

  • провода от диммера могут генерировать помехи на высоких частотах ШИМ
  • логарифмическая кривая диммирования у модуля. То есть нужно подбирать состояния клапана и значения уставки

В целом должно работать, однако реального опыта у меня нет.

1 лайк

Медленного для термоэлектрических вполне достаточно, вот так: Подключение термоэлектрических сервоприводов к WBIO-DO-SSR-8 или WBIO-DO-HS-8 - #6 от пользователя BrainRoot
У них очень большая инерционность.
Но встречается , даже довольно часто, - и применение WB-LED (WB-MRGBW-D) для низковольтных, либо WB-MDM3 для актуаторов “на 220”. Кстати, внутри актуаторы с “0-10” управлением, которые требуют переменный ток питания - так и устроены - в зависимости от управляющего наприяжения часть периодов просто пропускается.

В общем - “медленного” вполне достаточно, но и с диммерами - работает.

1 лайк

Эта тема была автоматически закрыта через 7 дней после последнего ответа. В ней больше нельзя отвечать.