Положение Солнца (Азимут) в Луа
В LUA есть только одна функция, которую я могу найти в интернете, но она дает неправильные значения (измеренные с помощью профессиональных онлайн-инструментов).
Оказывается, что от восхода солнца до некоторого времени после полудня математика работает, но после этого угол Солнца возвращается к положению восхода солнца. Должно быть от 106° до 253°, в настоящее время это от 106° до ~180° до 106°.Функция, которую я использую:
-- 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
Пример запроса:
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)
Результат это:
- -0,1 градуса по высоте 106 градусов по азимуту.
Результат должен быть:
- -0,1 градуса по высоте 253 градуса по азимуту.
Я нашел множество решений в других языках программирования и даже попытался переписать в Lua, но без всякого успеха. Слишком сложная математика стоит за решением.
Я использую его для моего Corona SDK приложения, которое покажет положение Солнца относительно устройство. Единственное решение, которое в настоящее время работает, - это скрипт PHP или Javascript, который мое приложение может запросить через вызов API через Интернет, но я действительно хотел бы избежать этого.
Я чрезвычайно благодарен за любую помощь со стороны сообщества. Спасибо и люблю вас, ребята! :)2 ответа:
Я нашел способ / хак, чтобы исправить эту проблему.
Функция все та же:
-- 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
Добавлен код, который исправил проблему:
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
И наконец, чтобы получить правильный результат:
lat, long = 45.327063, 14.442176 altitude, azimuth = getSunPos(lat, long, os.date('*t', os.time()))
Вот и все. Я был бы счастлив с полной функцией, которая делает математику правильно, но этого будет достаточно. Он работает и был протестирован на 3 местах по всему миру.