Posts: 57
Threads: 28
Joined: May 2018
Reputation:
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?
Posts: 57
Threads: 28
Joined: May 2018
Reputation:
1
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.
Posts: 7769
Threads: 42
Joined: Jun 2015
Reputation:
447
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.
Posts: 57
Threads: 28
Joined: May 2018
Reputation:
1
15.02.2021, 12:07
(This post was last modified: 15.02.2021, 12:12 by MantasJ.)
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?
Posts: 7769
Threads: 42
Joined: Jun 2015
Reputation:
447
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.
Posts: 57
Threads: 28
Joined: May 2018
Reputation:
1
Ok, but still, I don't understand some points:
- 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?
- 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?
- 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?
Posts: 7769
Threads: 42
Joined: Jun 2015
Reputation:
447
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 selfetoutput() 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.
|