Re: chauffage PID
Publié : 24 févr. 2018, 12:36
Mauvais nom de sonde probablement
Reprenez le contrôle de votre domotique
https://easydomoticz.com/forum/
Code : Tout sélectionner
--------------------------------
------ USER SETTINGS ------
--------------------------------
-- domoticz
domoticzIP = '192.168.1.130' --'127.0.0.1'
domoticzPORT = '8080'
--------------------------------
------ END ------
--------------------------------
-- régulation chauffage (PID)
function compute(pid)
local init = 0
-- récupération température
local temp = getTemp(pid['sonde'])
-- création variable : 4 dernières températures
if (uservariables['PID_temps_'..pid['zone']] == nil ) then
creaVar('PID_temps_'..pid['zone'],string.rep(temp..';',3)..temp)
init = 1
end
-- création variable : intégrale
if (uservariables['PID_integrale_'..pid['zone']] == nil ) then
creaVar('PID_integrale_'..pid['zone'],'0')
init = 1
end
if init == 1 then
log('PID '..pid['zone']..' initialisation..',pid['debug'])
return commandArray
end
-- définition des variables locales
local moy_erreur = 0
local n = 1
local somme_erreurs = 0
local heatTime
local marche
local arret
local tmp = {}
-- définition des commandes marche/arrêt
if pid['invert'] then
marche = 'Off' ; arret = 'On'
else
marche = 'On' ; arret = 'Off'
end
-- à chaque cycle
if ( time.min%pid['cycle'] == 0 ) then
-- maj des 4 dernières temps
local temps = string.match(uservariables['PID_temps_'..pid['zone']],";([^%s]+)")..";"..temp
commandArray['Variable:PID_temps_'..pid['zone']] = temps
-- si l'on veut chauffer
if ( otherdevices[pid['OnOff']] == 'On' ) then
-- récupération de la consigne
local consigne = tonumber(otherdevices_svalues[pid['thermostat']]) or pid['thermostat']
-- calcul de l'erreur
local erreur = consigne-temp
-- calcul intégrale auto consumée et moyenne erreur glissante
temps:gsub("([+-]?%d+%.*%d*)",function(t)
tmp[n] = tonumber(t)
err = tonumber(consigne-t)
somme_erreurs = somme_erreurs+err
moy_erreur = moy_erreur+err*n^3
n = n+1
end)
somme_erreurs = round(constrain(somme_erreurs,0,255),1)
moy_erreur = round(moy_erreur/100,2)
-- calcul de la dérivée (régression linéaire - méthode des moindres carrés)
local delta_erreurs = round((4*(4*tmp[1]+3*tmp[2]+2*tmp[3]+tmp[4])-10*(tmp[1]+tmp[2]+tmp[3]+tmp[4]))/20,2)
-- aux abords de la consigne, passage au second systême integrale
if somme_erreurs < 2 then
somme_erreurs = tonumber(uservariables['PID_integrale_'..pid['zone']])
-- re calcule intégrale si hors hysteresis
-- à moins d'un dixièmes de degré d'écart avec la consigne
-- le ratrapage est considéré OK, l'intégrale n'est pas recalculée
if math.abs(erreur) > 0.11 then
-- calcule intégrale
somme_erreurs = round(constrain(somme_erreurs+erreur/2,0,2),2)
-- maj
commandArray['Variable:PID_integrale_'..pid['zone']] = tostring(somme_erreurs)
end
end
-- calcul pid
local P = round(pid['Kp']*moy_erreur,2)
local I = round(pid['Ki']*somme_erreurs,2)
local D = round(pid['Kd']*delta_erreurs,2)
-- calcul de la commande en %
local commande = round(constrain(P+I+D,0,100))
-- calcul du temps de fonctionnement
if commande == 100 then
-- débordement de 20s pour ne pas couper avant recalcule
heatTime = (pid['cycle']*60)+20
elseif commande > 0 then
-- secu mini maxi
heatTime = round(constrain(commande*pid['cycle']*0.6,pid['secu'],(pid['cycle']*60)-pid['secu']))
elseif commande == 0 then
-- coupure retardée
heatTime = constrain(pid['secu']-lastSeen(pid['radiateur']),0,pid['secu'])
end
-- AFTER n'aime pas 1 ou 2..
if heatTime == 1 or heatTime == 2 then
heatTime = 0
end
-- action sur l'élément chauffant
if heatTime > 0 then
commandArray[1] = {[pid['radiateur']] = marche}
commandArray[2] = {[pid['radiateur']] = arret..' AFTER '..heatTime}
else
commandArray[pid['radiateur']]=arret
end
-- journalisation
if pid['debug'] then
log('PID zone: '..string.upper(pid['zone']))
log('température: '..temp..'°C pour '..consigne..'°C souhaité')
log('Kp: '..pid['Kp'])
log('Ki: '..pid['Ki'])
log('Kd: '..pid['Kd'])
log('erreur: '..moy_erreur)
log('∑ erreurs: '..somme_erreurs)
log('Δ erreurs: '..delta_erreurs)
log('P: '..P)
log('I: '..I)
log('D: '..D)
log('cycle: '..pid['cycle']..'min (sécu: '..pid['secu']..'s)')
-- avertissement si secu dépasse 1/4 du cycle
if ((100*pid['secu'])/(60*pid['cycle'])>25) then
warn('sécu trop importante, ralonger durée de cycle..')
end
log('commande: '..commande..'% ('..string.sub(os.date("!%X",heatTime),4,8):gsub("%:", "\'")..'\")')
log('')
end
end
end
-- toutes les 15 minutes, si on ne veut pas chauffer
if ( time.min%15 == 0 and otherdevices[pid['OnOff']] == 'Off' ) then
-- arrêt chauffage (renvoi commande systematique par sécurité)
commandArray[pid['radiateur']] = arret..' AFTER '..constrain(pid['secu']-lastSeen(pid['radiateur']),3,pid['secu'])
end
endCode : Tout sélectionner
-- Ce script permet réguler la température de la zone
-- chargement des modules
dofile('/home/pi/domoticz/scripts/lua/modules.lua')
--------------------------------
------ Variables à éditer ------
--------------------------------
local pid={}
pid['debug'] = true -- true pour voir les logs dans la console log Dz ou false pour ne pas les voir
pid['zone'] = 'Chambre Alicia' -- nom de la zone pour affichage dans les logs et distinction de variables
pid['sonde'] = 'T°C Chambre Alicia' -- Nom de la sonde de température
pid['OnOff'] = 'Thermostat Alicia PID' -- Nom de l'interrupteur virtuel de mise en route
pid['thermostat'] = 19 -- consigne ou 'nom' de l'interrupteur virtuel de thermostat
-- actionneur
pid['radiateur'] = 'Radiateur_Alicia' -- Nom de l'interrupteur de chauffage
pid['invert'] = true -- si On et Off doivent être inversé ou non
-- PID
pid['Kp'] = 45 -- Coefficient proportionnel
pid['Ki'] = 20 -- Coefficient intégrateur
pid['Kd'] = 45 -- Coefficient dérivateur
pid['cycle'] = 10 -- temps en minute d'un cycle PID
pid['secu'] = 30 -- temps mini en seconde entre 2 ordres opposés
--------------------------------
-- Fin des variables à éditer --
--------------------------------
commandArray = {}
compute(pid)
return commandArrayBonjour,vil1driver a écrit :J'avais donc vu juste.