LogicMachine Forum
PID to temperature not scale - Printable Version

+- LogicMachine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Scripting (https://forum.logicmachine.net/forumdisplay.php?fid=8)
+--- Thread: PID to temperature not scale (/showthread.php?tid=4157)



PID to temperature not scale - KoBra - 25.07.2022

Dears, i want a PID that calculates the supply water temp based on the setpoint and the actual temperature. But i have the PID script (see below) but i think the problem is i am keeping 0 is the fact that the output is in scale not temperature

-- clamp and set new output value
function PID2Confusedetoutput()
  local t, object, value, dt.scale


can somebody tell me how the datatype should be set to get the right output?

Code:
PID22 = {   -- default params   defaults = {     -- invert algorithm, used for cooling     inverted = true,     -- minimum output value     min = 5,     -- maximum output value     max = 30,     -- proportional gain     kp = 0.1,     -- integral gain     ki = 0.1,     -- derivative gain     kd = 0.1,   } } -- PID2 init, returns new PID2 object function PID2:init(params)   local n = setmetatable({}, { __index = PID2 })   local k, v   -- set user parameters   n.params = params   -- copy parameters that are set by user   for k, v in pairs(PID2.defaults) do     if n.params[ k ] == nil then       n.params[ k ] = v     end   end   -- reverse gains in inverted mode   if n.params.inverted then     n.params.kp = -n.params.kp     n.params.ki = -n.params.ki     n.params.kd = -n.params.kd   end   return n end -- resets algorithm on init or a switch back from manual mode function PID2:reset()   -- previous value   self.previous = grp.getvalue(self.params.current)   -- reset iterm   self.iterm = 0   -- last running time   self.lasttime = os.time()   -- clamp iterm   self:clampiterm() end -- clamps iterm value function PID2:clampiterm()   self.iterm = math.max(self.iterm, self.params.min)   self.iterm = math.min(self.iterm, self.params.max) end -- clamp and set new output value function PID2:setoutput()   local t, object, value, dt.scale   self.output = math.max(self.output, self.params.min)   self.output = math.min(self.output, self.params.max)   value = math.floor(self.output)   local t = type(self.params.output)   -- write to output if object is set   if t == 'string' or t == 'table' then     if t == 'string' then       self.params.output = { self.params.output }     end     for _, output in ipairs(self.params.output) do       grp.write(output, value)     end   end end -- algorithm step, returns nil when disabled or no action is required, output value otherwise function PID2:run()   local result   -- get manual mode status   local manual = self.params.manual and grp.getvalue(self.params.manual) or false   -- in manual mode, do nothing   if manual then     self.running = false   -- not in manual, check if reset is required after switching on   elseif not self.running then     self:reset()     self.running = true   end   -- compute new value if not in manual mode   if self.running then     -- get time between previous and current call     local now = os.time()     self.deltatime = now - self.lasttime     self.lasttime = now     -- run if previous call was at least 1 second ago     if self.deltatime > 0 then       result = self:compute()     end   end   return result end -- computes new output value function PID2:compute()   local current, setpoint, deltasc, deltain, output   -- get input values   current = grp.getvalue(self.params.current)   setpoint = grp.getvalue(self.params.setpoint)   -- delta between setpoint and current   deltasc = setpoint - current   -- calculate new iterm   self.iterm = self.iterm + self.params.ki * self.deltatime * deltasc   self:clampiterm()   -- delta between current and previous value   deltain = current - self.previous   -- calculate output value   self.output = self.params.kp * deltasc + self.iterm   self.output = self.output - self.params.kd / self.deltatime * deltain   -- write to output   self:setoutput()   -- save previous value   self.previous = current   return self.output end



RE: PID to temperature not scale - admin - 26.07.2022

Use this if the output data type is 2-byte floating point (float16).
Code:
function PID2:setoutput()   local t, object, value   self.output = math.max(self.output, self.params.min)   self.output = math.min(self.output, self.params.max)   value = self.output   local t = type(self.params.output)   -- write to output if object is set   if t == 'string' or t == 'table' then     if t == 'string' then       self.params.output = { self.params.output }     end     for _, output in ipairs(self.params.output) do       grp.write(output, value, dt.float16)     end   end end



RE: PID to temperature not scale - KoBra - 27.07.2022

(26.07.2022, 06:17)admin Wrote: Use this if the output data type is 2-byte floating point (float16).
Code:
function PID2:setoutput()   local t, object, value   self.output = math.max(self.output, self.params.min)   self.output = math.min(self.output, self.params.max)   value = self.output   local t = type(self.params.output)   -- write to output if object is set   if t == 'string' or t == 'table' then     if t == 'string' then       self.params.output = { self.params.output }     end     for _, output in ipairs(self.params.output) do       grp.write(output, value, dt.float16)     end   end end
tnx for the help, works perfectly


RE: PID to temperature not scale - KoBra - 27.07.2022

(27.07.2022, 09:48)KoBra Wrote:
(26.07.2022, 06:17)admin Wrote: Use this if the output data type is 2-byte floating point (float16).
Code:
function PID2:setoutput()   local t, object, value   self.output = math.max(self.output, self.params.min)   self.output = math.min(self.output, self.params.max)   value = self.output   local t = type(self.params.output)   -- write to output if object is set   if t == 'string' or t == 'table' then     if t == 'string' then       self.params.output = { self.params.output }     end     for _, output in ipairs(self.params.output) do       grp.write(output, value, dt.float16)     end   end end
tnx for the help, works perfectly

it is not as accurate as i hoped. Is there and easy fix to get temperature in 0,1 degree output?


RE: PID to temperature not scale - admin - 28.07.2022

Depending on the value range float16 type won't have 0.1 precision. In the original setoutput function there was a math.floor call that rounded the value down to an integer. You can log the output value before sending it like this:
Code:
function PID2:setoutput()   local t, object, value   self.output = math.max(self.output, self.params.min)   self.output = math.min(self.output, self.params.max)   value = self.output   log(value)   local t = type(self.params.output)   -- write to output if object is set   if t == 'string' or t == 'table' then     if t == 'string' then       self.params.output = { self.params.output }     end     for _, output in ipairs(self.params.output) do       grp.write(output, value, dt.float16)     end   end end