【问题标题】:R function for position of sun giving unexpected results太阳位置的 R 函数给出了意想不到的结果
【发布时间】:2017-01-16 12:55:29
【问题描述】:

我想根据时间、纬度和经度计算太阳的位置。我在这里找到了这个很好的问题和答案:Position of the sun given time of day, latitude and longitude。但是,当我评估函数时,我得到不正确的结果。鉴于答案的质量,我几乎可以肯定我的结果有问题,但我提出这个问题是为了尝试解决问题。

为方便起见,下面转载的函数代码如下:

astronomersAlmanacTime <- function(x)
{
  # Astronomer's almanach time is the number of 
  # days since (noon, 1 January 2000)
  origin <- as.POSIXct("2000-01-01 12:00:00")
  as.numeric(difftime(x, origin, units = "days"))
}

hourOfDay <- function(x)
{
  x <- as.POSIXlt(x)
  with(x, hour + min / 60 + sec / 3600)
}

degreesToRadians <- function(degrees)
{
  degrees * pi / 180
}

radiansToDegrees <- function(radians)
{
  radians * 180 / pi
}

meanLongitudeDegrees <- function(time)
{
  (280.460 + 0.9856474 * time) %% 360
}

meanAnomalyRadians <- function(time)
{
  degreesToRadians((357.528 + 0.9856003 * time) %% 360)
}

eclipticLongitudeRadians <- function(mnlong, mnanom)
{
  degreesToRadians(
      (mnlong + 1.915 * sin(mnanom) + 0.020 * sin(2 * mnanom)) %% 360
  )
}

eclipticObliquityRadians <- function(time)
{
  degreesToRadians(23.439 - 0.0000004 * time)
}

rightAscensionRadians <- function(oblqec, eclong)
{
  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] + 2 * pi 
  ra
}

rightDeclinationRadians <- function(oblqec, eclong)
{
  asin(sin(oblqec) * sin(eclong))
}

greenwichMeanSiderealTimeHours <- function(time, hour)
{
  (6.697375 + 0.0657098242 * time + hour) %% 24
}

localMeanSiderealTimeRadians <- function(gmst, long)
{
  degreesToRadians(15 * ((gmst + long / 15) %% 24))
}

hourAngleRadians <- function(lmst, ra)
{
  ((lmst - ra + pi) %% (2 * pi)) - pi
}

elevationRadians <- function(lat, dec, ha)
{
  asin(sin(dec) * sin(lat) + cos(dec) * cos(lat) * cos(ha))
}

solarAzimuthRadiansJosh <- function(lat, dec, ha, el)
{
  az <- asin(-cos(dec) * sin(ha) / cos(el))
  cosAzPos <- (0 <= sin(dec) - sin(el) * sin(lat))
  sinAzNeg <- (sin(az) < 0)
  az[cosAzPos & sinAzNeg] <- az[cosAzPos & sinAzNeg] + 2 * pi
  az[!cosAzPos] <- pi - az[!cosAzPos]
  az
}

solarAzimuthRadiansCharlie <- function(lat, dec, ha)
{
  zenithAngle <- acos(sin(lat) * sin(dec) + cos(lat) * cos(dec) * cos(ha))
  az <- acos((sin(lat) * cos(zenithAngle) - sin(dec)) / (cos(lat) * sin(zenithAngle)))
  ifelse(ha > 0, az + pi, 3 * pi - az) %% (2 * pi)
}

sunPosition <- function(when = Sys.time(), format, lat = 46.5, long = 6.5) 
{    
  if(is.character(when)) when <- strptime(when, format)
  time <- astronomersAlmanacTime(when)
  hour <- hourOfDay(when)

  # Ecliptic coordinates  
  mnlong <- meanLongitudeDegrees(time)   
  mnanom <- meanAnomalyRadians(time)  
  eclong <- eclipticLongitudeRadians(mnlong, mnanom)     
  oblqec <- eclipticObliquityRadians(time)

  # Celestial coordinates
  ra <- rightAscensionRadians(oblqec, eclong)
  dec <- rightDeclinationRadians(oblqec, eclong)

  # Local coordinates
  gmst <- greenwichMeanSiderealTimeHours(time, hour)  
  lmst <- localMeanSiderealTimeRadians(gmst, long)

  # Hour angle
  ha <- hourAngleRadians(lmst, ra)

  # Latitude to radians
  lat <- degreesToRadians(lat)

  # Azimuth and elevation
  el <- elevationRadians(lat, dec, ha)
  azJ <- solarAzimuthRadiansJosh(lat, dec, ha, el)
  azC <- solarAzimuthRadiansCharlie(lat, dec, ha)

  data.frame(
      elevation = radiansToDegrees(el), 
      azimuthJ  = radiansToDegrees(azJ),
      azimuthC  = radiansToDegrees(azC)
  )
}

如果我跑:

sunPosition(when = Sys.time(),lat = 43, long = -89)

结果是:

  elevation azimuthJ azimuthC
1 -24.56604 55.26111 55.26111

Sys.time() 给出:

> Sys.time()
[1] "2016-09-08 09:09:05 CDT"

现在是上午 9 点,太阳升起。使用http://www.esrl.noaa.gov/gmd/grad/solcalc/我得到124的方位角和38的仰角,我认为这是正确的。

我认为这可能是代码的问题,但我也从上面的答案中测试了 Josh 的原始 sunPosition 函数并得到了相同的结果。我的下一个想法是我的时间或时区有问题。


按照上述问题测试冬至,仍然给出了与他们发现的相同的结果并且看起来是正确的:

testPts <- data.frame(lat = c(-41,-3,3, 41), 
                      long = c(0, 0, 0, 0))

time <- as.POSIXct("2012-12-22 12:00:00")

sunPosition(when = time, lat = testPts$lat, long = testPts$long)

elevation azimuthJ azimuthC
1  72.43112 359.0787 359.0787
2  69.56493 180.7965 180.7965
3  63.56539 180.6247 180.6247
4  25.56642 180.3083 180.3083

当我做同样的测试,但改变经度 (-89) 时,我在中午得到一个负海拔。

testPts <- data.frame(lat = c(-41,-3,3, 41), 
                      long = c(-89, -89, -89, -89))

time <- as.POSIXct("2012-12-22 12:00:00 CDT")

sunPosition(when = time, lat = testPts$lat, long = testPts$long)

      elevation azimuthJ azimuthC
1  16.060136563 107.3420 107.3420
2   2.387033692 113.3522 113.3522
3   0.001378426 113.4671 113.4671
4 -14.190786786 108.8866 108.8866

【问题讨论】:

  • 我刚刚检查了所有 24 个时区的时间戳 2016-09-08 09:09:05 CDT,但没有一个给出 azimuthJ55.26azimuthC55.26。事实上,这两个值总是不同的。所以我认为您的代码中可能存在错误。
  • 嗯,很高兴知道。您是否运行我粘贴的代码并得到同样糟糕的结果?
  • 我得到的结果与你的相似,@Tedward:sunPosition(when = as.POSIXct("2016-09-08 09:09:05 CDT"),lat = 43, long = -89) 产生 -24.43463 55.45186 55.45186

标签: r geometry astronomy azimuth


【解决方案1】:

链接帖子中的核心代码没有任何问题如果输入when 以UTC 给出。令人困惑的是,OP 在网站中为2016-09-08 09:09:05 CDTSys.time() 输入了错误的Time Zone

使用http://www.esrl.noaa.gov/gmd/grad/solcalc/ 我得到124 的方位角和38 的仰角,我认为这是正确的。

输入到 NOAA 网站的正确 Time Zone-5 for CDT (see this website),它给出:

调用 sunPosition 并将时间调整为 UTC 会得到类似的结果:

sunPosition(when = "2016-09-08 14:09:05", format="%Y-%m-%d %H:%M:%S",lat = 43, long = -89)
##  elevation azimuthJ azimuthC
##1  28.08683 110.4915 110.4915

现在,代码不会转换为 UTC。一种方法是替换sunPosition 中的第一行:

if(is.character(when)) when <- strptime(when, format)

if(is.character(when)) 
  when <- strptime(when, format, tz="UTC")
else
  when <- as.POSIXlt(when, tz="UTC")

我们现在可以通过以下方式调用sunPosition

sunPosition(when = "2016-09-08 09:09:05-0500", format="%Y-%m-%d %H:%M:%S%z",lat = 43, long = -89)
##  elevation azimuthJ azimuthC
##1  28.08683 110.4915 110.4915

得到相同的结果。请注意,当以这种方式调用 sunPosition 时,我们需要在字符串文字和 format (%z) 中指定与 UTC 的偏移量。

有了这个变化,sunPosition 可以用Sys.time() 调用(我在东海岸):

Sys.time()
##[1] "2016-09-08 12:42:08 EDT"
sunPosition(Sys.time(),lat = 43, long = -89)
##  elevation azimuthJ azimuthC
##1  49.24068 152.1195 152.1195

与 NOAA 网站匹配

对于Time Zone = -4 对于EDT

【讨论】:

  • 感谢爱超的回答!正如您正确指出的那样,我的主要困惑是未能转换为 UTC。
【解决方案2】:

我认为问题在于经度。如果我将经度设置为 0,将纬度设置为我的纬度,将时间设置为我的时间,我会得到正确的仰角和方位角值。

> time <- Sys.time()
> time

[1] "2016-09-08 12:07:35 CDT"

> sunPosition(when = time, lat = 43, long = 0)

 elevation azimuthJ azimuthC
1  52.36687 184.1056 184.1056

在我看来,经度是相对于您的位置的经度。我不是这个主题的专家,但在某种程度上,经度会这样是有道理的,因为它对太阳位置没有太大影响。在给定本地时间处于给定纬度的人将看到太阳在天空中的相同位置,与处于不同经度的其他人相同,但纬度和本地时间相同(忽略时区是具有离散边界和地球的分箱区域的复杂性绕着太阳转)。

也许我没有很好地阅读问题或函数,但是经度的这种行为是出乎意料的。


编辑: 阅读@aichao 的答案说明了为什么将纬度设置为零并使本地时间大致工作。但是,我认为这不会很准确。

【讨论】:

    猜你喜欢
    • 2018-10-28
    • 2014-06-22
    • 1970-01-01
    • 2014-05-24
    • 2019-05-19
    • 2017-01-05
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多