DEFINITION MODULE SunPath;
(*******************************************************************
Module SunPath (Version 1.1)
Copyright (c) 1989-2006 by Thomas Nemecek and ETH Zurich.
Purpose Compute solar angles, daylength,
real solar time, etc.
Remarks Units:
angles: radians
time: fraction of day (24h = 1.0)
except where the variable name
"hours" is used
Initialization:
the module is initialised for julian day = 1;
position, zone time = Zürich, Switzerland;
winter time.
WARNING: Implementation is such that computations
are done with limited accuracy.
References:
Meteonorm - Theorie für den Solarplaner.
BA f. Energiewirtschaft, 3003 Bern; 1985.
France, J. & Thornley, J.H.M (1984):
Mathematical models in agriculture, Butterworths,
London.
Programming
o Design
Thomas Nemecek 24/10/1989
Andreas Fischlin 13/08/2007
o Implementation
Thomas Nemecek 25/10/1989
Andreas Fischlin 13/08/2007
ETH Zurich
Systems Ecology
CHN E 35.1
Universitaetstrasse 16
8092 Zurich
SWITZERLAND
URLs:
<mailto:RAMSES@env.ethz.ch>
<http://www.sysecol.ethz.ch>
<http://www.sysecol.ethz.ch/SimSoftware/RAMSES>
Last revision of definition: 13/08/2007 af
*******************************************************************)
(***************************************)
(*##### Angle transformations #####*)
(***************************************)
PROCEDURE Rad(deg: REAL): REAL;
PROCEDURE Deg(rad: REAL): REAL;
(**************************************)
(*##### Time transformations #####*)
(**************************************)
PROCEDURE DayFraction(hours, minutes, seconds: INTEGER): REAL;
PROCEDURE DayFractionToTime(dayFraction: REAL; VAR hours, minutes, seconds: INTEGER);
PROCEDURE FractionOfYear (dayOfYear: INTEGER; dayfraction: REAL): REAL;
(*
Returns fraction of year where dayOfYear = 1 ~ 1st January;
dayOfYear = 365 (not leap year) or 366 (leap year) ~ 31st
December and dayfraction is a number in [0.0..1.0].
*)
(***************************************)
(*##### Set location and time #####*)
(***************************************)
(*----------------------------*)
(*===== Set location =====*)
(*----------------------------*)
PROCEDURE SetGeogrLocation( latitude, longitude: REAL);
PROCEDURE GetGeogrLocation(VAR latitude, longitude: REAL);
(* latitude and longitude are to be defined as degrees and fractions
thereof.
Latitude: N ==> >0 S ==> <0
Longitude: W ==> >0 E ==> <0
*)
PROCEDURE SetTimeZone( hours: REAL);
PROCEDURE GetTimeZone(VAR hours: REAL);
(*
Difference between standard time (local time NOT adjusted
for daylight saving time or winter time) and UT or UTC.
Ex.: Switzerland (East of Greenwich): time zone = -1h.
*)
PROCEDURE SetTimeDelay( hours: REAL);
PROCEDURE GetTimeDelay(VAR hours: REAL);
(*
Time delay relative to time zone to correct for daylight
saving time. Typically summer time: +1.0; winter time:
0.0. The routines from this module know nothing about
daylight saving time rules. You need to call this
routine with hours = 0 at a switch from daylight saving
to standard or winter time or with typically hours = 1 at
a date when daylight saving time becomes active. Note,
this module knows nothing about daylight saving time
rules and will always add the specified time delay
'hours' in any computation involving local time. Ex.:
Switzerland: winter time (=standard time): hours = 0.0;
daylight saving time (from 3rd Sunday in March till last
Sunday in October): hours = 1.0. For other locations see
e.g. <http://en.wikipedia.org/wiki/Time_zone>.
*)
(*------------------------*)
(*===== Set time =====*)
(*------------------------*)
(*
Following routines are to be used to set the current day
within the year. You can freely use either SetJulianDay or
SetDayOfYear to achieve the same effect. You need to call
one of these set routines to use any solar position routine
for another day than 1st January (module initialization).
*)
PROCEDURE SetDayOfYear( dayOfYear: INTEGER);
PROCEDURE GetDayOfYear(VAR dayOfYear: INTEGER);
(* dayOfYear = 1 ~ 1st January;
dayOfYear = 365 (not leap year) or 366 (leap year) ~ 31st December
see also modules JulianDays (ScienceLib) and WriteDatTim (AuxLib)
*)
PROCEDURE SetJulianDay( julianDay: INTEGER);
PROCEDURE GetJulianDay(VAR julianDay: INTEGER);
(* same as SetDayOfYear, GetDayOfYear. Must not be confounded
with a true Julian Day (see also module JulianDays. Only kept
for upward compatibility reasons. *)
(********************************)
(*##### Sun's position #####*)
(********************************)
CONST
delta0 = 0.4092797096; (* declination of the Earth in radians *)
PROCEDURE SolarTime(localTime: REAL): REAL;
(*
Returns for the day as set by SetDayOfYear or
SetJulianDay the solar time given the localTime (=
standard time possibly adjusted for daylight saving time)
at a location with the time zone as defined by last call
to procedures and SetTimeDelay. The solar time is
defined to be 0 at noon (note, latitude as well as
longitude are ignored).
*)
PROCEDURE LocalTime(solarTime: REAL): REAL;
(*
Returns for the day as set by SetDayOfYear or
SetJulianDay the local time (= standard time possibly
adjusted for daylight saving time) given solarTime at a
location with the time zone as defined by last call to
procedures SetTimeZone and SetTimeDelay (note, latitude
as well as longitude are ignored). Standard time (=
winter time) is the local time without any adjustments
for daylight saving and defined by a multiple of half
hours offset from UT.
*)
PROCEDURE Noon(): REAL;
(*
Returns local time (= standard time) of true solar noon
for the day as set by SetDayOfYear or SetJulianDay at a
location with latitude and longitude as given in last
call to SetGeogrLocation and with the time zone as
defined by last call to procedures SetTimeZone and
SetTimeDelay.
*)
PROCEDURE SunHeightMax(): REAL; (* [1] Eq.13 *)
(* = SunHeight(Noon)); see procedure SunHeight *)
PROCEDURE SunHeight(localTime: REAL): REAL; (* [1] Eq.7 *)
(*
Returns the angle between the horizontal plane and the
sun (measured vertically from the point on the horizon
directly under the sun (cf. azimuth) up to the sun).
for the day as set by SetDayOfYear or SetJulianDay at a
location with latitude and longitude as given in last
call to SetGeogrLocation and with the time zone as
defined by last call to procedures SetTimeZone and
SetTimeDelay.
*)
PROCEDURE SunAzimuth(localTime: REAL): REAL; (* [1] Eq.8 *)
(*
Returns the south based azimuth, i.e. the angle between
the south direction and the sun for any given local time
(= standard time) for the day as set by SetDayOfYear or
SetJulianDay at a location with latitude and longitude as
given in last call to SetGeogrLocation and with the time
zone as defined by last call to procedures SetTimeZone
and SetTimeDelay. The returned angle lies between -Pi
and +Pi, solar time noon having an azimuth of 0. Often
azimuths are also given clockwise from true north to the
point on the horizon directly below the sun. To compute
the latter add Pi() (~180.0°) to the value returned by
SunAzimuth.
*)
(*
Zenith angle z
--------------
In following procedures the parameter z is the zenith angle
in radians between the sun and the zenith (The zenith being
the "top of the sky", i.e. the point on the imaginary
celestial sphere right above the head of the observer).
Depending on how exactly you define sunset and sunrise, the
following values are commonly used for z when computing day
length, sunset, sunrise:
- 90° (centre of the sun's disc is on the horizon, defining
astronomical sunset or sunrise);
- 90.8333° (upper margin of the sun's disc is on the horizon
given sun's radius or half of angular diameter corresponds
to 0.26667° and assuming a mean reffraction of 0.5667°, see
below z0);
- 96° (including civil twilight, which starts and ends when
the sun's centre is 6° below the horizon);
- 102° (nautical twilight, which starts and ends when the
sun's centre is more than 6° but less than 12° below the
horizon);
- 108° (astronomical twilight, which starts and ends when the
sun's centre is more than 12° but less than 18° below the
horizon)
*)
VAR z0: REAL; (* READ ONLY variable *)
(* = Rad(90.8333); see above "zenith angle z" *)
PROCEDURE DayLength(z: REAL): REAL; (* [2] Eq. 6.14 *)
(*
Returns the day length as a fraction of a day. Multiply
by 1440=360*4 (1 day ~ 360°, 1° ~ 4 minutes of elapsed
time) to obtain this value in minutes (of time).
<http://www.sunlit-design.com/infosearch/equationoftime.php>
*)
PROCEDURE SunRiseTime(z: REAL): REAL;
(*
Returns local time (= standard time) of sunrise for the
day as set by SetDayOfYear or SetJulianDay at a location
with latitude and longitude as given in last call to
SetGeogrLocation and with the time zone as defined by
last call to procedures SetTimeZone and SetTimeDelay.
*)
PROCEDURE SunSetTime(z: REAL): REAL;
(* As SunRiseTime but for sunset *)
(***************************)
(*##### Auxiliary #####*)
(***************************)
PROCEDURE EquationOfTime(): REAL;
(*
Difference between solar time and universal standard time
UT (or UTC) here returned as a fraction of a day
(multiply by 1440=360*4 (1 day ~ 360°, 1° ~ 4 minutes of
elapsed time) to obtain this value in minutes of time).
<http://www.sunlit-design.com/infosearch/equationoftime.php>
*)
PROCEDURE Delta(): REAL;
(*
Declination of the Sun in radian (angle between sun rays
and the plane of the earth equator). Delta is 0.0 at the
equinoxes and at a maximum at the solstices (+23°27' or
-23°27'). e.g. <http://en.wikipedia.org/wiki/Declination#Sun>
*)
END SunPath.