This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Pid
#1
Hello everyone,
I hope you're all well. I'm writing to you because I'm having a problem with a script related to a PI controller for a radiant floor heating system. The system consists of a 0/10 valve and a flow sensor. To prevent the controller from becoming too sensitive to temperature variations, a moving average filter was added. However, despite this precaution, the PID remains very lazy and unstable.
I've attached the script and an image of the configured parameters. The setpoints, proportional, and integral values are adjustable via the supervisory system. I feel like I'm a bit lost in the dark, so I'm counting on your expert help to resolve this situation. I forgot about the Pt1000 sensors read by the KNX module with a 2-minute cyclic variation and a value change of 0.2K, but the valves are 0/10 controlled by the KNX module.
Thank you so much for your support and availability.
Michael

-- ============================================================
-- REGOLATORE PI – MISCELATRICE PAVIMENTO RADIANTE
-- SOLO SONDA MANDATA
-- ============================================================

---------------------------------------------------------------
-- PARAMETRI BASE (persistenti)
---------------------------------------------------------------
local Kp = storage.get('Kp_PINT') or 3.0
local Ki = storage.get('Ki_PINT') or 0.02
local integral = storage.get('integral_PINT') or 0
local last_mode = storage.get('last_mode')

---------------------------------------------------------------
-- CONFIGURAZIONE KNX
---------------------------------------------------------------
local group_mode        = '5/0/0'    -- 1=inverno / 0=estate
local group_in          = '5/2/1'    -- temperatura mandata
local group_out        = '5/0/1'    -- 0–10 V miscelatrice
local group_set_winter  = '5/2/4'
local group_set_summer  = '5/2/5'----
local group_kp          = '5/2/6'
local group_ki          = '5/2/7'

---------------------------------------------------------------
-- COSTANTI DI CONTROLLO
---------------------------------------------------------------
local cycle_time = 120          -- secondi
local filter_samples = 3        -- filtro ridotto
local out_min, out_max = 0, 100 -- %
local max_delta = 2            -- base rampa
local deadband = 0.3            -- °C

---------------------------------------------------------------
-- VARIABILI
---------------------------------------------------------------
local readings = {}
local last_output = storage.get('last_output') or 0

---------------------------------------------------------------
-- MEDIA MOBILE TEMPERATURA MANDATA
---------------------------------------------------------------
local function moving_average(v)
  if type(v) ~= 'number' then return nil end
  table.insert(readings, v)
  if #readings > filter_samples then
    table.remove(readings, 1)
  end
  local s = 0
  for _, x in ipairs(readings) do
    s = s + x
  end
  return s / #readings
end

---------------------------------------------------------------
-- CICLO PRINCIPALE
---------------------------------------------------------------
while true do

  -------------------------------------------------------------
  -- Aggiornamento Kp / Ki da KNX
  -------------------------------------------------------------
  local v = grp.getvalue(group_kp)
  if type(v) == 'number' then
    Kp = v
    storage.set('Kp_PINT', Kp)
  end

  v = grp.getvalue(group_ki)
  if type(v) == 'number' then
    Ki = v
    storage.set('Ki_PINT', Ki)
  end

  -------------------------------------------------------------
  -- Modalità estate / inverno
  -------------------------------------------------------------
  local is_winter = grp.getvalue(group_mode) and true or false

  if last_mode ~= is_winter then
    integral = 0
    last_mode = is_winter
    storage.set('last_mode', is_winter)
  end

  -------------------------------------------------------------
  -- Setpoint
  -------------------------------------------------------------
  local set = is_winter
    and grp.getvalue(group_set_winter)
    or  grp.getvalue(group_set_summer)

  if type(set) ~= 'number' then
    set = is_winter and 35 or 25
  end

  -------------------------------------------------------------
  -- Temperatura mandata filtrata
  -------------------------------------------------------------
  local T = grp.getvalue(group_in)
  local Tf = moving_average(T)

  if Tf then

    -----------------------------------------------------------
    -- LIMITI TEMPERATURA MANDATA
    -----------------------------------------------------------
    local Tmax  = set + 2.0
    local Tstop = set + 3.0

    -----------------------------------------------------------
    -- ERRORE
    -------------------------------------------------------

Attached Files Thumbnail(s)
   
.txt   Regolatore PI Michael.txt (Size: 6.47 KB / Downloads: 7)
Reply


Forum Jump: