Câu hỏi này đã được hỏi trước đây hơn ba năm. Đã có một câu trả lời được đưa ra, tuy nhiên tôi đã tìm thấy giải pháp có trục trặc.
Mã bên dưới bằng R. Tôi đã chuyển nó sang ngôn ngữ khác, tuy nhiên, tôi đã kiểm tra mã gốc trực tiếp trong R để đảm bảo vấn đề không xảy ra với quá trình chuyển của tôi.
sunPosition <- function(year, month, day, hour=12, min=0, sec=0,
lat=46.5, long=6.5) {
twopi <- 2 * pi
deg2rad <- pi / 180
# Get day of the year, e.g. Feb 1 = 32, Mar 1 = 61 on leap years
month.days <- c(0,31,28,31,30,31,30,31,31,30,31,30)
day <- day + cumsum(month.days)[month]
leapdays <- year %% 4 == 0 & (year %% 400 == 0 | year %% 100 != 0) & day >= 60
day[leapdays] <- day[leapdays] + 1
# Get Julian date - 2400000
hour <- hour + min / 60 + sec / 3600 # hour plus fraction
delta <- year - 1949
leap <- trunc(delta / 4) # former leapyears
jd <- 32916.5 + delta * 365 + leap + day + hour / 24
# The input to the Atronomer's almanach is the difference between
# the Julian date and JD 2451545.0 (noon, 1 January 2000)
time <- jd - 51545.
# Ecliptic coordinates
# Mean longitude
mnlong <- 280.460 + .9856474 * time
mnlong <- mnlong %% 360
mnlong[mnlong < 0] <- mnlong[mnlong < 0] + 360
# Mean anomaly
mnanom <- 357.528 + .9856003 * time
mnanom <- mnanom %% 360
mnanom[mnanom < 0] <- mnanom[mnanom < 0] + 360
mnanom <- mnanom * deg2rad
# Ecliptic longitude and obliquity of ecliptic
eclong <- mnlong + 1.915 * sin(mnanom) + 0.020 * sin(2 * mnanom)
eclong <- eclong %% 360
eclong[eclong < 0] <- eclong[eclong < 0] + 360
oblqec <- 23.429 - 0.0000004 * time
eclong <- eclong * deg2rad
oblqec <- oblqec * deg2rad
# Celestial coordinates
# Right ascension and declination
num <- cos(oblqec) * sin(eclong)
den <- cos(eclong)
ra <- atan(num / den)
ra[den < 0] <- ra[den < 0] + pi
ra[den >= 0 & num < 0] <- ra[den >= 0 & num < 0] + twopi
dec <- asin(sin(oblqec) * sin(eclong))
# Local coordinates
# Greenwich mean sidereal time
gmst <- 6.697375 + .0657098242 * time + hour
gmst <- gmst %% 24
gmst[gmst < 0] <- gmst[gmst < 0] + 24.
# Local mean sidereal time
lmst <- gmst + long / 15.
lmst <- lmst %% 24.
lmst[lmst < 0] <- lmst[lmst < 0] + 24.
lmst <- lmst * 15. * deg2rad
# Hour angle
ha <- lmst - ra
ha[ha < -pi] <- ha[ha < -pi] + twopi
ha[ha > pi] <- ha[ha > pi] - twopi
# Latitude to radians
lat <- lat * deg2rad
# Azimuth and elevation
el <- asin(sin(dec) * sin(lat) + cos(dec) * cos(lat) * cos(ha))
az <- asin(-cos(dec) * sin(ha) / cos(el))
elc <- asin(sin(dec) / sin(lat))
az[el >= elc] <- pi - az[el >= elc]
az[el <= elc & ha > 0] <- az[el <= elc & ha > 0] + twopi
el <- el / deg2rad
az <- az / deg2rad
lat <- lat / deg2rad
return(list(elevation=el, azimuth=az))
}
Vấn đề tôi đang gặp phải là phương vị nó trả về có vẻ sai. Ví dụ: nếu tôi chạy hàm vào ngày hạ chí (miền nam) lúc 12:00 cho các vị trí 0ºE và 41ºS, 3ºS, 3ºN và 41ºN:
> sunPosition(2012,12,22,12,0,0,-41,0)
$elevation
[1] 72.42113
$azimuth
[1] 180.9211
> sunPosition(2012,12,22,12,0,0,-3,0)
$elevation
[1] 69.57493
$azimuth
[1] -0.79713
Warning message:
In asin(sin(dec)/sin(lat)) : NaNs produced
> sunPosition(2012,12,22,12,0,0,3,0)
$elevation
[1] 63.57538
$azimuth
[1] -0.6250971
Warning message:
In asin(sin(dec)/sin(lat)) : NaNs produced
> sunPosition(2012,12,22,12,0,0,41,0)
$elevation
[1] 25.57642
$azimuth
[1] 180.3084
Những con số này có vẻ không đúng. Độ cao mà tôi hài lòng - hai cái đầu tiên phải gần bằng nhau, cái thứ ba thấp hơn một chút và cái thứ tư thấp hơn nhiều. Tuy nhiên, phương vị đầu tiên phải là hướng Bắc, trong khi con số mà nó đưa ra thì hoàn toàn ngược lại. Ba điểm còn lại sẽ gần đúng hướng Nam, tuy nhiên chỉ có cái cuối cùng làm được. Hai điểm ở giữa chỉ cách Bắc, một lần nữa ra ngoài 180º.
Như bạn có thể thấy, cũng có một số lỗi được kích hoạt với các vĩ độ thấp (gần đường xích đạo)
Tôi tin rằng lỗi nằm trong phần này, với lỗi được kích hoạt ở dòng thứ ba (bắt đầu bằng elc
).
# Azimuth and elevation
el <- asin(sin(dec) * sin(lat) + cos(dec) * cos(lat) * cos(ha))
az <- asin(-cos(dec) * sin(ha) / cos(el))
elc <- asin(sin(dec) / sin(lat))
az[el >= elc] <- pi - az[el >= elc]
az[el <= elc & ha > 0] <- az[el <= elc & ha > 0] + twopi
Tôi tìm kiếm xung quanh và tìm thấy một đoạn mã tương tự trong C, được chuyển đổi thành R dòng nó sử dụng để tính toán góc phương vị sẽ giống như
az <- atan(sin(ha) / (cos(ha) * sin(lat) - tan(dec) * cos(lat)))
Kết quả đầu ra ở đây dường như đang đi đúng hướng, nhưng tôi không thể đưa nó cho tôi câu trả lời đúng mọi lúc khi nó được chuyển đổi trở lại độ.
Việc sửa mã (nghi ngờ nó chỉ là vài dòng ở trên) để làm cho nó tính toán đúng phương vị sẽ thật tuyệt vời.