|
1 | 1 | """ |
2 | 2 | PSA |
3 | 3 |
|
4 | | -Solar position algorithm based on PSA's implementation. |
| 4 | +Solar position algorithm based on PSA's implementation [1]. |
| 5 | +
|
| 6 | +[1] M. Blanco, D. Alarcón, T. López, and M. Lara, "Computing the Solar |
| 7 | +Vector," Solar Energy, vol. 70, no. 5, 2001, |
| 8 | +:doi:`10.1016/S0038-092X(00)00156-0` |
| 9 | +[2] M. Blanco, K. Milidonis, and A. Bonanos, "Updating the PSA sun |
| 10 | +position algorithm," Solar Energy, vol. 212, 2020, |
| 11 | +:doi:`10.1016/j.solener.2020.10.084` |
5 | 12 | """ |
6 | 13 |
|
7 | 14 | struct PSA <: SolarAlgorithm end |
@@ -46,53 +53,48 @@ const PSA_PARAMS = Dict{Int,SVector{15,Float64}}( |
46 | 53 | """ |
47 | 54 | _solar_position( |
48 | 55 | obs::Observer{T}, |
49 | | - dt::ZonedDateTime, |
| 56 | + dt::DateTime, |
50 | 57 | ::PSA, |
51 | 58 | ) -> SolarPos{T} |
52 | 59 | PSA algorithm implementation stub. |
53 | 60 | """ |
54 | 61 | function _solar_position( |
55 | 62 | obs::Observer{T}, |
56 | | - dt::ZonedDateTime, |
| 63 | + dt::DateTime, |
57 | 64 | ::PSA; |
58 | 65 | coeffs::Int = 2020, |
59 | 66 | ) where {T} |
60 | | - |
61 | 67 | p = PSA_PARAMS[coeffs] |
62 | 68 |
|
63 | | - phi = obs.latitude_rad |
64 | | - lambda_t = obs.longitude_rad |
65 | | - |
66 | | - # extract date components |
67 | | - h = fractional_hour(dt) |
68 | | - |
69 | | - # julian day calculation |
| 69 | + # elapsed julian days (n) since J2000.0 |
70 | 70 | jd = Dates.datetime2julian(dt) |
71 | | - n = jd - 2451545.0 |
72 | | - |
73 | | - # ecliptic longitude and obliquity |
74 | | - omega = p[1] + p[2] * n |
75 | | - L = p[3] + p[4] * n |
76 | | - g = p[5] + p[6] * n |
77 | | - lambda_e = L + p[7] * sin(g) + p[8] * sin(2 * g) + p[9] + p[10] * sin(omega) |
78 | | - epsilon = p[11] + p[12] * n + p[13] * cos(omega) |
| 71 | + n = jd - 2451545.0 # Eq. 2 |
79 | 72 |
|
80 | | - # right ascension and declination |
81 | | - ra = atan(cos(epsilon) * sin(lambda_e), cos(lambda_e)) % (2 * pi) |
82 | | - δ = asin(sin(epsilon) * sin(lambda_e)) |
| 73 | + # ecliptic coordinates of the sun |
| 74 | + # ecliptic longitude (λₑ), and obliquity of the ecliptic (ϵ) |
| 75 | + Ω = p[1] + p[2] * n # Eq. 3 |
| 76 | + L = p[3] + p[4] * n # Eq. 4 |
| 77 | + g = p[5] + p[6] * n # Eq. 5 |
| 78 | + λₑ = L + p[7] * sin(g) + p[8] * sin(2 * g) + p[9] + p[10] * sin(Ω) # Eq. 6 |
| 79 | + ϵ = p[11] + p[12] * n + p[13] * cos(Ω) # Eq. 7 |
83 | 80 |
|
84 | | - # local coordinates |
85 | | - gmst = p[14] + p[15] * n + h |
86 | | - lmst = gmst + lambda_t # check units if gmst in hours |
87 | | - w = lmst - ra |
| 81 | + # celestial right ascension (ra) and declination (d) |
| 82 | + ra = atan(cos(ϵ) * sin(λₑ), cos(λₑ)) # Eq. 8 |
| 83 | + ra = mod(ra, 2π) |
| 84 | + δ = asin(sin(ϵ) * sin(λₑ)) # Eq. 9 |
88 | 85 |
|
89 | | - theta_z = acos(cos(phi) * cos(w) * cos(δ) + sin(δ) * sin(phi)) |
90 | | - gamma = atan(-sin(w), (tan(δ) * cos(phi) - sin(phi) * cos(w))) |
| 86 | + # computes the local coordinates: azimuth (γ) and zenith angle (θz) |
| 87 | + ϕ = obs.latitude_rad |
| 88 | + hour = fractional_hour(dt) |
| 89 | + gmst = p[14] + p[15] * n + hour # Eq. 10 |
| 90 | + λt = rad2deg(obs.longitude_rad) |
| 91 | + lmst = (gmst * 15 + λt) * π / 180 # Eq. 11 |
| 92 | + ω = lmst - ra # Eq. 12 |
| 93 | + θz = acos(cos(ϕ) * cos(ω) * cos(δ) + sin(δ) * sin(ϕ)) # Eq. 13 |
| 94 | + γ = atan(-sin(ω), (tan(δ) * cos(ϕ) - sin(ϕ) * cos(ω))) # Eq. 14 |
91 | 95 |
|
92 | | - # Earth mean radius correction |
93 | | - EMR = 6371.01 |
94 | | - AU = 149597890 |
95 | | - theta_z += (EMR / AU) * sin(theta_z) |
| 96 | + # parallax correction |
| 97 | + θz = θz + (EMR / AU) * sin(θz) # Eq. 15,16 |
96 | 98 |
|
97 | | - return SolarPos{T}(pi / 2 - theta_z, theta_z, gamma) # elevation, zenith, azimuth in radians |
| 99 | + return SolarPos(mod(rad2deg(γ), 360), rad2deg(π / 2 - θz), rad2deg(θz)) |
98 | 100 | end |
0 commit comments