Skip to content

Commit 6887c61

Browse files
committed
Enhance solar position calculations by adding standard time and fractional hour functions, and update related algorithms and tests
1 parent ec95fe7 commit 6887c61

File tree

8 files changed

+91
-27
lines changed

8 files changed

+91
-27
lines changed

src/Basic/Basic.jl

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ export BasicAlgorithm
1313
using PVSimBase.GeoLocation: Location
1414
using DocStringExtensions
1515
using TimeZones
16-
using DynamicQuantities: Quantity
16+
using DynamicQuantities
1717
using Interfaces
1818

1919
using SolarPosition.PositionInterface: SolarPositionAlgorithm, SolarPositionInterface,
20-
declination, equation_of_time, offset_hours
20+
declination, equation_of_time, offset_hours,
21+
standard_time, fractional_hour
2122
import ..PositionInterface
2223

2324
"""
@@ -28,18 +29,47 @@ struct BasicAlgorithm <: SolarPositionAlgorithm
2829
end
2930

3031
function PositionInterface.sunpos(algorithm::BasicAlgorithm, timestamp::ZonedDateTime)
31-
longitude = algorithm.location.longitude
32-
latitude = algorithm.location.latitude
3332

3433
# declination [deg]
3534
β = declination(timestamp)
3635

37-
# Local standard Time Merdidian [deg]
38-
LSTM = 15 * offset_hours(timestamp)
36+
# Longitude of the standard Time Merdidian [deg]
37+
λ_LSTM = 15 * offset_hours(timestamp)us"deg"
3938

40-
# equation of time
41-
E_qt = equation_of_time(timestamp)
42-
return (Quantity(0.0, deg = 1), Quantity(0.0, deg = 1))
39+
# Local longitude / latitude [deg]
40+
λ_local = algorithm.location.longitude
41+
ϕ_local = algorithm.location.latitude
42+
43+
# Local time, without daylights saving time [h]
44+
T_local = fractional_hour(standard_time(timestamp)) * us"h"
45+
46+
# equation of time from [deg] to [h], 360 deg = 24 h
47+
E_qt = equation_of_time(timestamp) * 24us"h" / 360us"deg"
48+
println("Timestamp: ", timestamp)
49+
println("E_qt: ", E_qt)
50+
println("T_local: ", T_local)
51+
println("λ_LSTM: ", λ_LSTM)
52+
println("λ_local: ", λ_local)
53+
println("ϕ_local: ", ϕ_local)
54+
println("β: ", β)
55+
56+
# solar time [h]
57+
T_solar = T_local + E_qt + (λ_LSTM - λ_local) / 15us"deg/h"
58+
println("T_solar: ", T_solar)
59+
60+
# hour angle [deg]
61+
H = 15us"deg/h" * (12us"h" - T_solar)
62+
println("H: ", H)
63+
64+
# solar elevation angle [deg]
65+
α = asind(sind(β.value) * sind(ϕ_local.value) +
66+
cosd(β.value) * cosd(ϕ_local.value) * cosd(H.value))
67+
68+
# solar azimuth angle [deg]
69+
A = acosd((sind(β.value) * cosd(ϕ_local.value) -
70+
cosd(β.value) * sind(ϕ_local.value) * cosd(H.value)) / cosd(α))
71+
return (
72+
Quantity(α, SymbolicDimensions, deg = 1), Quantity(A, SymbolicDimensions, deg = 1))
4373
end
4474

4575
algorithm = BasicAlgorithm(Location(latitude = 0.0, longitude = 0.0))

src/PositionInterface/PositionInterface.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module PositionInterface
22

33
using Interfaces
4-
using DynamicQuantities: Quantity
4+
using DynamicQuantities
55
using Dates
66
using PVSimBase
77
using TimeZones

src/PositionInterface/angles.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The output is a `Quantity` with the unit of degrees.
1515
function declination(d::Number)
1616
(0 <= d <= 365) || throw(ArgumentError("day of the year must be in the range [0, 365]"))
1717
δ = -23.45cosd((360 / 365) * (d + 10))
18-
return Quantity(δ, deg = 1)
18+
return Quantity(δ, SymbolicDimensions, deg = 1)
1919
end
2020

2121
"""

src/PositionInterface/time.jl

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export equation_of_time, offset_hours
1+
export equation_of_time, offset_hours, standard_time, fractional_hour
22

33
"""
44
equation_of_time(t::Union{Number, DateTime})
@@ -36,11 +36,11 @@ function equation_of_time(jd::Number)
3636
# Ecliptic latitude of the Sun.
3737
λ_ecliptic = mod(λ_m + 1.914666471sin_Ms + 0.019994643sin_2Ms, 360) |> deg2rad
3838

39-
# Compute the equation of time [rad].
39+
# Compute the equation of time [deg].
4040
eot = -1.914666471sin_Ms - 0.019994643sin_2Ms + 2.466sin(2λ_ecliptic) -
4141
0.0053sin(4λ_ecliptic)
4242

43-
return Quantity(eot, deg = 1)
43+
return Quantity(eot, SymbolicDimensions, deg = 1)
4444
end
4545

4646
"""
@@ -57,4 +57,24 @@ equation_of_time(t::ZonedDateTime) = equation_of_time(DateTime(t))
5757
Return the offset in hours of the timezone `tz` with respect to UTC-0.
5858
"""
5959
offset_hours(tz::FixedTimeZone) = Hour(tz.offset.std).value
60-
offset_hours(t::ZonedDateTime) = offset_hours(FixedTimeZone(t))
60+
offset_hours(t::ZonedDateTime) = offset_hours(FixedTimeZone(t))
61+
62+
"""
63+
standard_time(t::ZonedDateTime)
64+
65+
Get the standard time of a given `ZonedDateTime` object.
66+
"""
67+
standard_time(t::ZonedDateTime) = t.utc_datetime + t.zone.offset.std
68+
69+
"""
70+
fractional_hour(t::DateTime)
71+
72+
Get the current time as a fraction x/24 of the day.
73+
"""
74+
# fractional_hour(t::ZonedDateTime) = hour(t) + minute(t) / 60 + second(t) / 3600
75+
# dt = t - floor(t, Hour(24))
76+
function fractional_hour(t::DateTime)
77+
dt = t - floor(t, Hour(24))
78+
return Float64(dt.value) / (60 * 60 * 1000)
79+
end
80+
fractional_hour(t::ZonedDateTime) = fractional_hour(DateTime(t))

src/SolarPositionAlgorithms/SolarPositionAlgorithms.jl

Lines changed: 0 additions & 3 deletions
This file was deleted.

test/test-angles.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"""
1010

1111
using Dates: DateTime
12-
using DynamicQuantities: Quantity
12+
using DynamicQuantities
1313
using SolarPosition.PositionInterface
1414

1515
@testset "Function declination" begin

test/test-interfaces.jl

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
1-
using TimeZones: now, TimeZone
1+
using TimeZones
2+
using Dates
23
using Interfaces
34

45
using PVSimBase.GeoLocation: Location
56
using SolarPosition.Basic
67
using SolarPosition.PositionInterface
78

8-
@testset "Basic algorithm" begin
9-
test_location = Location(latitude = 0.0, longitude = 0.0)
10-
alg = BasicAlgorithm(test_location)
11-
@test alg isa BasicAlgorithm
12-
@test alg.location == test_location
13-
pos = sunpos(alg, now(TimeZone("UTC")))
9+
# @testset "Basic algorithm" begin
10+
# test_location = Location(latitude = 0.0, longitude = 0.0)
11+
# alg = BasicAlgorithm(test_location)
12+
# @test alg isa BasicAlgorithm
13+
# @test alg.location == test_location
14+
# pos = sunpos(alg, now(TimeZone("UTC")))
15+
# end
16+
17+
@testset "Algorithms" begin
18+
# latitude, longitude, timestamp, elevation, azimuth
19+
cases = [
20+
(39.743, -105.178,
21+
ZonedDateTime(2020, 2, 10, 0, 0, TimeZone("UTC-7")), -39.44us"deg", 75.84us"deg")
22+
]
23+
24+
for (lat, lon, ts, el, az) in cases
25+
loc = Location(latitude = lat, longitude = lon)
26+
alg = BasicAlgorithm(loc)
27+
pos = sunpos(alg, ts)
28+
@test pos[1]el atol=1.0us"deg"
29+
@test pos[2]az atol=1.0us"deg"
30+
end
1431
end
1532

1633
@testset "PositionInterfaces" begin

test/test-time.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"""
1010

1111
using Dates: DateTime
12-
using DynamicQuantities: Quantity
12+
using DynamicQuantities
1313
using SolarPosition.PositionInterface
1414

1515
@testset "Function equation_of_time" begin

0 commit comments

Comments
 (0)