LogicMachine Forum
Outside compensation curve - 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: Outside compensation curve (/showthread.php?tid=1770)



Outside compensation curve - oyvindnordbo - 04.12.2018

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?


RE: Outside compensation curve - admin - 04.12.2018

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



RE: Outside compensation curve - oyvindnordbo - 04.12.2018

Yes wee need a curve besause all values is going to be able to change in the visualizatione


RE: Outside compensation curve - admin - 04.12.2018

This might be helpful: http://lua-users.org/wiki/SimpleFit


RE: Outside compensation curve - Daniel - 04.12.2018

There is block in match advance curve function with 2 points, it might be good starting point.


RE: Outside compensation curve - merel - 04.12.2018

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))



RE: Outside compensation curve - jerryhenke - 16.01.2025

(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)



RE: Outside compensation curve - Erwin van der Zwart - 16.01.2025

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)



RE: Outside compensation curve - jerryhenke - 16.01.2025

(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



RE: Outside compensation curve - Erwin van der Zwart - 17.01.2025

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


RE: Outside compensation curve - admin - 17.01.2025

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)



RE: Outside compensation curve - Erwin van der Zwart - 17.01.2025

Great! This makes it so much easier to use in many cases (:


RE: Outside compensation curve - jerryhenke - 17.01.2025

(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