Posts: 41
Threads: 9
Joined: Jan 2016
Reputation:
0
I have tried to make an outside compensation curve for a heating system in the FB editor, but do not find out completely of unwanted blocks that are most powerful to use.
I need to write from four groups
-10 ° C = 45 ° C
-5 ° C = 40 ° C
0 ° C = 35 ° C
5 ° C = 30 ° C
In order to get a set point out of what outdoor temperature it is, is this possible?
Posts: 8066
Threads: 43
Joined: Jun 2015
Reputation:
469
Do you really need a curve here? From your data it looks like simple linear compensation, for each 5 degrees of temperature the setpoint is lowered by 5 degrees:
Code: setpoint = 35 - temperature
Posts: 41
Threads: 9
Joined: Jan 2016
Reputation:
0
Yes wee need a curve besause all values is going to be able to change in the visualizatione
Posts: 8066
Threads: 43
Joined: Jun 2015
Reputation:
469
Posts: 4929
Threads: 28
Joined: Aug 2017
Reputation:
225
There is block in match advance curve function with 2 points, it might be good starting point.
------------------------------
Ctrl+F5
Posts: 29
Threads: 6
Joined: Jan 2016
Reputation:
4
Hello.
You can try this:
Code: function linear_by_table(input,curve,offset)
local FDY = offset or 0
fk1= (curve["y"][1] - curve["y"][2]) / (curve["x"][1] - curve["x"][2])
fk2= (curve["y"][2] - curve["y"][3]) / (curve["x"][2] - curve["x"][3])
fk3= (curve["y"][3] - curve["y"][4]) / (curve["x"][3] - curve["x"][4])
if input < curve["x"][1] then
out = curve["y"][1] + FDY;
elseif input >= curve["x"][1] and input < curve["x"][2] then
out = fk1 * (input - curve["x"][1]) + curve["y"][1] + FDY
elseif input >= curve["x"][2] and input < curve["x"][3] then
out = fk2 * (input - curve["x"][2]) + curve["y"][2] + FDY
elseif input >= curve["x"][3] and input < curve["x"][4] then
out = fk3 * (input - curve["x"][3]) + curve["y"][3] + FDY
else
out = curve["y"][4] + FDY
end
return out
end
curve = {}
curve["x"] = {-20,-10,0,20}
curve["y"] = {80,70,65,18}
--offset=2
--log(linear_by_table(20,curve,offset))
log(linear_by_table(-15,curve))
Posts: 14
Threads: 1
Joined: Sep 2024
Reputation:
0
16.01.2025, 11:42
(This post was last modified: 16.01.2025, 11:43 by jerryhenke.
Edit Reason: added code
)
(04.12.2018, 13:45)merel Wrote: Hello.
You can try this:
Code: function linear_by_table(input,curve,offset)
local FDY = offset or 0
fk1= (curve["y"][1] - curve["y"][2]) / (curve["x"][1] - curve["x"][2])
fk2= (curve["y"][2] - curve["y"][3]) / (curve["x"][2] - curve["x"][3])
fk3= (curve["y"][3] - curve["y"][4]) / (curve["x"][3] - curve["x"][4])
if input < curve["x"][1] then
out = curve["y"][1] + FDY;
elseif input >= curve["x"][1] and input < curve["x"][2] then
out = fk1 * (input - curve["x"][1]) + curve["y"][1] + FDY
elseif input >= curve["x"][2] and input < curve["x"][3] then
out = fk2 * (input - curve["x"][2]) + curve["y"][2] + FDY
elseif input >= curve["x"][3] and input < curve["x"][4] then
out = fk3 * (input - curve["x"][3]) + curve["y"][3] + FDY
else
out = curve["y"][4] + FDY
end
return out
end
curve = {}
curve["x"] = {-20,-10,0,20}
curve["y"] = {80,70,65,18}
--offset=2
--log(linear_by_table(20,curve,offset))
log(linear_by_table(-15,curve))
Wow. Thanks! Used this today and made some small changes.
My code looks like this and runs nicely.
Code: function linear_by_table(input, curve, offset)
local FDY = offset or 0
local n = #curve["x"] -- Number of points
if n ~= #curve["y"] then
error("x and y lists must have the same number of values")
end
local out
if input < curve["x"][1] then
out = curve["y"][1] + FDY
elseif input >= curve["x"][n] then
out = curve["y"][n] + FDY
else
for i = 1, n - 1 do
if input >= curve["x"][i] and input < curve["x"][i + 1] then
local fk = (curve["y"][i + 1] - curve["y"][i]) / (curve["x"][i + 1] - curve["x"][i])
out = fk * (input - curve["x"][i]) + curve["y"][i] + FDY
break
end
end
end
return out
end
-- Define the curve for interpolation
local curve = {x = {-20, -10, 0, 10, 20}, y = {42, 34, 32, 25, 15}}
-- Adjust offset to shift the entire curve
local offset = 0
-- Get outdoor temperature from KNX address 0/3/0
local outdoor_temp = grp.getvalue('0/3/0')
-- Calculate the flow setpoint based on the outdoor temperature
local flow_setpoint = linear_by_table(outdoor_temp, curve, offset)
-- Write the calculated value to KNX address 5/5/0
grp.write('5/5/0', flow_setpoint)
-- Log the results
log('Outdoor temperature: ' .. outdoor_temp .. ', Flow setpoint: ' .. flow_setpoint)
Posts: 1793
Threads: 6
Joined: Jul 2015
Reputation:
120
For the outdoor temp combined with a curve i usually use a 3 days average, this can simply be done by attaching a trend to your measurement object and use this small script.
Code: require('trends')
dateslastthreedays = {}
dateslastthreedays['start'] = os.date('*t', os.time() - (86400 * 4))
dateslastthreedays['end'] = os.date('*t', os.time() - (86400 * 1))
threedaysaverage = trends.fetchone('OUTDOOR TEMP', dateslastthreedays)
Posts: 14
Threads: 1
Joined: Sep 2024
Reputation:
0
16.01.2025, 21:56
(This post was last modified: 16.01.2025, 22:04 by jerryhenke.)
(16.01.2025, 17:08)Erwin van der Zwart Wrote: For the outdoor temp combined with a curve i usually use a 3 days average, this can simply be done by attaching a trend to your measurement object and use this small script.
Code: require('trends')
dateslastthreedays = {}
dateslastthreedays['start'] = os.date('*t', os.time() - (86400 * 4))
dateslastthreedays['end'] = os.date('*t', os.time() - (86400 * 1))
threedaysaverage = trends.fetchone('OUTDOOR TEMP', dateslastthreedays)
The only trend I have right now is outdoor temperature with a 5-min resolution.
I tried your script and can't really make it work.
I get incorrect values. I would rather like to use a span of the last 9 hours average temperature or so, not from four days agou until yesterday which i read your script.
I tried change 86400 * 4 to 86400 * 1 and the "end" to 86400 * 0, but that gives 0 as temperature.
Any good suggestions?
Quote:require('trends')
-- Define time range for the timespan
local lastninehours = {}
lastninehours['start'] = os.date('*t', os.time() - (3600 * 9)) -- 9 hours back
lastninehours['end'] = os.date('*t', os.time()) -- Current time
-- Fetch the average temperature for the timespan
local ninehoursaverage = trends.fetchone('Utetemp', lastninehours)
-- Fetch the current temperature from KNX address 0/3/0
local currenttemperature = grp.getvalue('0/3/0') -- Assumes grp.getvalue function is used
if ninehoursaverage and currenttemperature then
-- Calculate the highest value between the average temperature and the current temperature
local highesttemperature = math.max(ninehoursaverage, currenttemperature)
-- Send the highest value to KNX address 5/5/20
grp.write('5/5/20', highesttemperature)
-- Log both the average temperature and the temperature sent
log("Average temperature for the last 9 hours: " .. tostring(ninehoursaverage))
log("Temperature sent to 5/5/20: " .. tostring(highesttemperature))
else
log("Could not fetch the average temperature or the current temperature.")
end
Posts: 1793
Threads: 6
Joined: Jul 2015
Reputation:
120
You always fetch a full day, that is why my sample is using yesterday until 4 days back, so 3 full days..
From the knowledge base ( time values are ignored) :
Code: dates - Lua table with two items - start and end, each item must contain year, month, day keys, time values (hours, minutes and seconds) are ignored
You can get today via:
Code: require('trends')
local today = {}
today['start'] = os.date('*t', os.time())
today['end'] = os.date('*t', os.time() + 86400)
-- Fetch the average temperature for the timespan
local todayaverage = trends.fetchone('Temperatuur Woonkamer', today)
log(todayaverage)
To see the full data used just change -> trends.fetchone into -> trends.fetch, here you will see all samples of today
Posts: 8066
Threads: 43
Joined: Jun 2015
Reputation:
469
KB doc needs updating. It's possible to fetch data for the given period if start/end is a not a table but a timestamp number.
Fetch data for the last hour:
Code: date = os.date('*t') -- current date as a table
time = os.time(date, true) -- convert UTC timestamp
-- fetch data for the last hour (3600 seconds)
datarange = {
['start'] = time - 3600,
['end'] = time,
}
data = trends.fetch('trend name', datarange)
log(data)
Posts: 1793
Threads: 6
Joined: Jul 2015
Reputation:
120
Great! This makes it so much easier to use in many cases (:
Posts: 14
Threads: 1
Joined: Sep 2024
Reputation:
0
17.01.2025, 10:24
(This post was last modified: 17.01.2025, 10:26 by jerryhenke.)
(17.01.2025, 08:18)admin Wrote: KB doc needs updating. It's possible to fetch data for the given period if start/end is a not a table but a timestamp number.
Fetch data for the last hour:
Code: date = os.date('*t') -- current date as a table
time = os.time(date, true) -- convert UTC timestamp
-- fetch data for the last hour (3600 seconds)
datarange = {
['start'] = time - 3600,
['end'] = time,
}
data = trends.fetch('trend name', datarange)
log(data)
Amazing. Now it seems to work.
I ended up with this script for a damped outdoor temperatur that i later use for my control of floor heating.
Thougts?
Also - do I have to define the resolution of the trend log that I use? Now mine is 5 minutes, but I am also starting a 1 hour-resolution trend log of outside temperature. I imagine less work for LM to calculate the average if I have a table with less values?
Quote:require('trends')
-- Function to calculate time range based on hours and days
local function get_time_range(start_hours, start_days, end_hours, end_days)
local date = os.date('*t') -- current date and time as a table
local current_time = os.time(date, true) -- convert to UTC timestamp
local start_time = current_time - (3600 * start_hours + 86400 * start_days) -- calculate start time
local end_time = current_time - (3600 * end_hours + 86400 * end_days) -- calculate end time
return {
['start'] = start_time,
['end'] = end_time
}
end
-- Define time range (replace the number of hours and days with your values)
local start_hours_back = 0 -- hours back from current time for start time
local start_days_back = 1 -- days back from current time for start time
local end_hours_back = 0 -- hours back from current time for end time
local end_days_back = 0 -- days back from current time for end time
local time_range = get_time_range(start_hours_back, start_days_back, end_hours_back, end_days_back)
-- Specify resolution for 5-minute data (360 seconds)
local resolution = 360
-- Fetch average temperature for the time period with specified resolution
local periodaverage = trends.fetchone('Utetemp', time_range, resolution)
-- Fetch the current temperature from KNX address 0/3/0
local currenttemperature = grp.getvalue('0/3/0') -- Assuming grp.getvalue function is used
if periodaverage and currenttemperature then
-- Calculate the highest value between the average temperature and the current temperature
local highesttemperature = math.max(periodaverage, currenttemperature)
-- Send the highest value to KNX address 5/5/20
grp.write('5/5/20', highesttemperature)
-- Log both the average temperature and the temperature sent
log("Average temperature for selected period: " .. tostring(periodaverage))
log("Temperature sent to 5/5/20: " .. tostring(highesttemperature))
log("Current temperature at 0/3/0: " .. tostring(currenttemperature))
else
log("Could not fetch the average temperature or the current temperature.")
end
|