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 whether you accept or reject these cookies being set.

PID Problem
#1
Hello guys,

I'm trying to create a PID controller. I need to have 12 controllers - 1 P, 1 PI and 10 PID with D gain values ranging from 0.1 to 1. P and PI controllers has to have P gain according to 6K, and PI controller I gain has to be according to 150min, so (6K/150min). Here is my script:

Code:
local P_value     =     6
local I_value     =     150
local kp     =     1/P_value
local ki    =     (kp/(I_value*60))*100

if not P then
 
P = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_P_Output',
    kp                     =     kp,
    ki                     =     0,
    kd                     =     0
})
 
end

P:run()

if not PI then

PI = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PI_Output',
    kp                     =     kp,
    ki                     =     ki,
    kd                     =     0
})
 
end

PI:run()

if not PID then
 
for i = 1, 10, 1 do
 
PID = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID' .. i .. '_Output',
    kp                     =     kp,
    ki                     =     ki,
    kd                     =     0.1 * i
})

PID:run() 
   
end
 
end

What I end up getting on P and PI controller outputs is 0, and on PID outputs I don't get anything with current setpoint being 24C while current temperature is 22.5C, so it's not correct. My resident script sleep time is 10sec, I have added PID algorithm in library so the problem is not coming from there. What is going on here? What am I missing?
Reply
#2
So I've changed the script a bit, it now looks like this:

Code:
local P_value     =     6
local I_value     =     150
local kp_value     =     0.16
local ki_value    =     0.0017

if not P then
 
P = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_P_Output',
    kp                     =     kp_value,
    ki                     =     0,
    kd                     =     0
})

PI = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PI_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0
})
 
PID1 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID1_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0.1
})
 
PID2 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID2_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0.2
}) 

PID3 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID3_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0.3
}) 
   
PID4 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID4_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0.4
})
 
PID5 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID5_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0.5
})
 
PID6 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID6_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0.6
})
 
PID7 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID7_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0.7
})
 
PID8 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID8_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0.8
})
 
PID9 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID9_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     0.9
})
 
PID10 = PID:init({
    current         =     'RTC05_Current_Temperature',
    setpoint         =     'RTC05_Setpoint_Temperature_Status',
    output             =     'BD_PID10_Output',
    kp                     =     kp_value,
    ki                     =     ki_value,
    kd                     =     1
})
 
end
 
P:run()
PI:run()
PID1:run()
PID2:run()
PID3:run()
PID4:run()
PID5:run()
PID6:run()
PID7:run()
PID8:run()
PID9:run()
PID10:run()


Setpoint is 23C and current temperature is 22.3C. All controllers give out 0 percent. Why? I have tried enabling/disabling the script, changing kp and ki values with and without calculation formula (example above is without) - didn't help.
Reply
#3
Your Kp value is too low. Set all gains to 1 and see how the system operates. Note that for correct PID loop operation it must be connected an actual output that affects the temperature, otherwise it's pointless.
Reply
#4
Hello, admin,

Thanks for the response!

What do you mean by kp value too low? As I've mentioned before, I'm trying to achieve (6K/150min) control, which would translate to kp value being 0.16 (1/6K-->0.16), or I'm calculating something wrong?

I've tried putting in kp equal to 1, but all outputs still give out 0. Current temp - 22.5C, setpoint - 23C.

I'm trying to simulate different controls, output isn't connected to valves right now, but I just need some information from trend logs for now.

I also added 1sec delay after each run:

Code:
local P_value = 6
local I_value = 150
local kp_value = 1
local ki_value = 0.0017
local delay = 1

if not P then

P = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_P_Output',
    kp = kp_value,
    ki = 0,
    kd = 0
})

PI = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PI_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0
})

PID1 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID1_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0.1
})

PID2 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID2_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0.2
})

PID3 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID3_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0.3
})
  
PID4 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID4_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0.4
})

PID5 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID5_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0.5
})

PID6 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID6_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0.6
})

PID7 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID7_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0.7
})

PID8 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID8_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0.8
})

PID9 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID9_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 0.9
})

PID10 = PID:init({
    current = 'RTC05_Current_Temperature',
    setpoint = 'RTC05_Setpoint_Temperature_Status',
    output = 'BD_PID10_Output',
    kp = kp_value,
    ki = ki_value,
    kd = 1
})

end

P:run()
os.sleep(delay)
PI:run()
os.sleep(delay)
PID1:run()
os.sleep(delay)
PID2:run()
os.sleep(delay)
PID3:run()
os.sleep(delay)
PID4:run()
os.sleep(delay)
PID5:run()
os.sleep(delay)
PID6:run()
os.sleep(delay)
PID7:run()
os.sleep(delay)
PID8:run()
os.sleep(delay)
PID9:run()
os.sleep(delay)
PID10:run()


Update: Okay, so I've set ki to 1 aswell, and now PI and PID controllers give out 11 percent, and add 10 percent every minute, which is way too fast. How do I achieve (6K/150min) control? And why P controller still gives out 0?
Reply
#5
Since the output is not connected your test won't show any real data because PID requires feedback from the system to operate. As I've mentioned start with a single PID controller with all 3 gains set to 1. You have to see how it operates in real conditions before applying any tuning. Trend log will help you to see how high the system oscillations are.
Reply
#6
Ok, but still, I don't understand some points:


  1. If I want to achieve, let's say some kind of control right from the start (I don't want P I and D values to be 1), I want the controller to behave like other KNX PI controllers and be able to set parameters like this - x Kelvin/y minutes, can I do this or it's impossible?
  2. Why P controller gives out 0 percent even if its value is 1? Other gains for I and D parts are 0, but that shouldn't affect the output, just that the output should be very "bouncy". Should I leave it on for more time for it to do something?
  3. At the end result, this is what I'm trying to achieve - I have a KNX PI controller controlling underfloor heating valves, which control parameters are set to (6K/150min) and I want to see, what happens if I take out "I" part out of the controller and what happens if I put some kind of "D" part in the controller. So my thought was to create identical controller in LM, create P controller with 6K parameter, PI controller with same parameters as KNX one have and a PID controller, with D part ranging in values from 0 to 1. Then from trend logs I would monitor all controllers outputs and see what kind of responses I get to different setpoints/temperatures and make some conclusions. So, in overall, is it possible to do this with LM or not?
Reply
#7
When only Kp is set each run will change the output value by the delta between the current temperature and the setpoint. You might need several runs for the output value to change if the delta is small. Resident script sleep time controls how frequently the algorithm runs. You can edit the PID library and add log(self.output) before selfConfusedetoutput() to see the raw output value (floating point).

As I've already told simulating PID like this is pointless. In real world situation changing the output value will change the temperature so the algorithm will produce different output values based on how the temperature changes. It's possible to make a script that will change the temperature based on the output value to check how gain values affect the speed of change. But you need a different sets of objects for each PID controller and it will still be very approximate unless you have some complex calculations that can simulate system inertia which is quite big for underfloor heating.
Reply


Forum Jump: