There is only one function in LUA I could find online, but it gives wrong values (measured with professional online tools).
It appears that from the sunrise till some time after the noon the math works, but after, the Sun's angle goes back to the sunrise position. Should be from 106° to 253°, currently it's from 106° to ~180° to 106°.
Function I'm using:
-- solar altitude, azimuth (degrees)
function sunposition(latitude, longitude, time)
time = time or os.time()
if type(time) == 'table' then time = os.time(time) end
local date = os.date('*t', time)
local timezone = (os.time(date) - os.time(os.date('!*t', time))) / 3600
if date.isdst then timezone = timezone + 1 end
local utcdate = os.date('*t', time - timezone * 3600)
local latrad = math.rad(latitude)
local fd = (utcdate.hour + utcdate.min / 60 + utcdate.sec / 3600) / 24
local g = (2 * math.pi / 365.25) * (utcdate.yday + fd)
local d = math.rad(0.396372 - 22.91327 * math.cos(g) + 4.02543 * math.sin(g) - 0.387205 * math.cos(2 * g)
+ 0.051967 * math.sin(2 * g) - 0.154527 * math.cos(3 * g) + 0.084798 * math.sin(3 * g))
local t = math.rad(0.004297 + 0.107029 * math.cos(g) - 1.837877 * math.sin(g)
- 0.837378 * math.cos(2 * g) - 2.340475 * math.sin(2 * g))
local sha = 2 * math.pi * (fd - 0.5) + t + math.rad(longitude)
local sza = math.acos(math.sin(latrad) * math.sin(d) + math.cos(latrad) * math.cos(d) * math.cos(sha))
local saa = math.acos((math.sin(d) - math.sin(latrad) * math.cos(sza)) / (math.cos(latrad) * math.sin(sza)))
return 90 - math.deg(sza), math.deg(saa)
end
Example request:
lat, long = 45.327063, 14.442176 -- Rijeka, Croatia
time = {year=2016, month=2, day=17, hour=17, min=30} -- end of the day
altitude, azimuth = sunposition(lat, long, time)
Result is:
Result should be:
I have found multiple solutions in other programming languages and even tried to rewrite in Lua but without any success. Too complex math behind the solution.
I'm using it for my Corona SDK app that will show position of the Sun relative to the device. The only solution that currently works is a PHP or Javascript script that my app can ask via API call over the Internet but I would really like to avoid that.
I'm extremely grateful for any help from the community. Thank you and love you folks! :)
I have found a way/hack to fix this issue.
Function is still the same:
-- solar altitude, azimuth (degrees)
function sunposition(latitude, longitude, time)
time = time or os.time()
if type(time) == 'table' then time = os.time(time) end
local date = os.date('*t', time)
local timezone = (os.time(date) - os.time(os.date('!*t', time))) / 3600
if date.isdst then timezone = timezone + 1 end
local utcdate = os.date('*t', time - timezone * 3600)
local latrad = math.rad(latitude)
local fd = (utcdate.hour + utcdate.min / 60 + utcdate.sec / 3600) / 24
local g = (2 * math.pi / 365.25) * (utcdate.yday + fd)
local d = math.rad(0.396372 - 22.91327 * math.cos(g) + 4.02543 * math.sin(g) - 0.387205 * math.cos(2 * g)
+ 0.051967 * math.sin(2 * g) - 0.154527 * math.cos(3 * g) + 0.084798 * math.sin(3 * g))
local t = math.rad(0.004297 + 0.107029 * math.cos(g) - 1.837877 * math.sin(g)
- 0.837378 * math.cos(2 * g) - 2.340475 * math.sin(2 * g))
local sha = 2 * math.pi * (fd - 0.5) + t + math.rad(longitude)
local sza = math.acos(math.sin(latrad) * math.sin(d) + math.cos(latrad) * math.cos(d) * math.cos(sha))
local saa = math.acos((math.sin(d) - math.sin(latrad) * math.cos(sza)) / (math.cos(latrad) * math.sin(sza)))
return 90 - math.deg(sza), math.deg(saa)
end
The added code that fixed the issue:
function getSunPos(lat, long, time)
findTime = {}
findTime.hour, findTime.min = time.hour, time.min
fixedAzimuthLast, fixedAzimuth = 0, 0
for i=0,23 do
for j=0,59 do
time.hour, time.min = i, j
local altitude, azimuth = sunposition(lat, long, time)
-- fix azimuth
if fixedAzimuthLast < azimuth then
fixedAzimuthLast = azimuth
fixedAzimuth = fixedAzimuthLast
else
fixedAzimuth = fixedAzimuthLast + (180 - azimuth)
end
-- find azimuth at target time
if findTime.hour == i and findTime.min == j then
-- final result
return altitude, fixedAzimuth
end
end
end
end
And finally to get the correct result:
lat, long = 45.327063, 14.442176
altitude, azimuth = getSunPos(lat, long, os.date('*t', os.time()))
That is it. I would be happier with the complete function that does the math correctly but this will suffice. It works and was tested on 3 locations globally.