Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ControllerObj = {}
- require("lib")
- function ControllerObj:new()
- local obj = obj or {}
- setmetatable(obj, {__index = self})
- obj.isEnabled = false
- obj.p = 1.0 -- proportional gain
- obj.tn = 1.0 -- integral reset time
- obj.d = 0.0 -- derivative
- obj.dFilter = 0 -- derivative filter time (in cylces)
- obj.dError = false -- use error for derivative. if false, use value
- obj.sp = 10.0 -- setpoint
- obj.pv = 0.0
- obj.intMax = 100.0 -- integral max
- obj.intMin = 0.0 -- integral min
- obj.outMax = 100.0 -- output max
- obj.outMin = 0.0 -- output min
- obj.error = 0.0 -- gain
- obj.errorLast = 0.0 -- last error
- obj.errorList = {}
- obj.dCalcLast = 0.0 -- last value used for derivative calculation
- obj.dCalcList = {} -- smoothing buffer
- obj.dCalcSum = 0.0 --
- obj.int = 0.0 -- integral
- obj.deriv = 0 -- derivative
- obj.cv = 0 -- output
- obj.tLast = os.epoch("utc")
- obj.firstCall = true
- return obj
- end
- function ControllerObj:update(pv)
- -- time delta calc so the integral is more accurate and the controller doesnt fluctuate with bad server tickrates
- -- os.epoch("utc") is used because its far more accurate than os.time
- local tNow = os.epoch("utc")
- local tDelta = (tNow - self.tLast) / 1000
- if tDelta <= 0 or tDelta >= 10 then
- tDelta = 1
- end
- self.pv = pv
- -- immediately exit if the controller is disabled
- if not self.isEnabled then
- return 0.0
- end
- -- gain
- self.error = (self.sp - self.pv) * self.p
- -- integral
- if self.tn <= 0 then
- self.int = 0.0
- elseif self.cv < self.outMax and self.cv > self.outMin then -- anti windup
- if self.int + self.error + self.deriv >= self.outMax then
- self.int = self.outMax - (self.error + self.deriv)
- else
- self.int = ((self.error / self.tn) * tDelta) + self.int
- end
- end
- if self.int <= self.intMin then self.int = self.intMin end
- if self.int >= self.intMax then self.int = self.intMax end
- -- derivative
- local dVal = 0.0
- if self.dError then
- dVal = self.error -- error derivative
- else
- dVal = -(self.pv*self.p) -- value RoC derivative
- end
- if self.d >= 0 then
- if self.dFilter > 0 then
- self.dCalcSum = smooth(self.dCalcList, dVal, self.dFilter)
- self.deriv = ((self.dCalcSum - self.dCalcLast) * self.d)*tDelta
- self.dCalcLast = self.dCalcSum
- else
- self.dCalcSum = 0.0
- self.deriv = ((dVal - self.dCalcLast) * self.d)*tDelta
- self.dCalcLast = dVal
- end
- else
- self.deriv = 0
- end
- self.tLast = os.epoch("utc")
- -- output
- self.cv = self.error + self.int + self.deriv
- if self.cv <= self.outMin then self.cv = self.outMin end
- if self.cv >= self.outMax then self.cv = self.outMax end
- if self.firstCall and self.cv >= self.outMax then self.int = 0 end
- self.firstCall = false
- return self.cv
- end
- function ControllerObj:setEnabled(bool)
- self.isEnabled = bool or false
- if not self.isEnabled then
- self:reset()
- end
- end
- function ControllerObj:setGain(gain)
- self.p = gain
- end
- function ControllerObj:setResetTime(time)
- self.tn = time
- end
- function ControllerObj:setDerivative(deriv)
- self.d = deriv
- end
- function ControllerObj:setDerivativeMode(bool)
- self.dError = bool
- end
- function ControllerObj:setDerivativeFilter(cycles)
- self.dFilter = cycles
- end
- function ControllerObj:setSetpoint(sp)
- self.sp = sp
- end
- function ControllerObj:setIntegralMax(max)
- self.intMax = max
- end
- function ControllerObj:setIntegralMin(min)
- self.intMin = min
- end
- function ControllerObj:setOutputMax(max)
- self.outMax = max
- end
- function ControllerObj:setOutputMin(min)
- self.outMin = min
- end
- function ControllerObj:reset() -- reset the controller values to 0
- self.error = 0.0
- self.int = 0.0
- self.deriv = 0.0
- self.cv = 0.0
- self.errorList = {}
- self.firstCall = false
- end
- function ControllerObj:getPV()
- return self.pv
- end
- function ControllerObj:getCV()
- return self.cv
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement