![]() |
Search   |
|
|
This is the source code for Sun Class.
This is just to take a look at before you download -- if you want to download it, then download all the solar classes here: Solar Tools Source
'Solar Analysis Tools - 'Copyright (C) 2005 Gary Reysa (gary@BuildItSolar.com)
' This program is free software; you can redistribute it and/or modify it ' under the terms of the GNU General Public License as published by the Free ' Software Foundation; either version 2 of the License, or (at your option) ' any later version.
' This program is distributed in the hope that it will be useful and encourage ' further development of solar tools, but WITHOUT ANY WARRANTY; without even ' the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ' See the GNU General Public License for more details.
' Sun Class -- Instances of Sun represent the sun ' Given the inputs: Date, Time, Longitude, Latitude and Altitude (abv sea level) ' The sun object will provide solar position and clear day solar radiation data. ' It is assumed that the time inputs to sun class are LOCAL SOLAR TIME. ' ' The calcs are based on the Lunde book, Solar Thermal Engineering. ' ' Azimuth is measured from true South. ' + azimuths are to East, - to West ' (see note below) ' ' NOTE: Azimuth is measured from Due South. ' Internally, Sun Class uses the convention of + azimuth to West, and - to East ' (this is the convention Lunde used in this calc in his book) ' Since this is counter to + rotations being CCW when viewed from the + Z direction, ' I always change the Azimuth angles sign, and reverse the Y component on the ' ToSunVector calcs before making them available as properties. ' ' Checked a number of dates and times -- seems to work well -- returns data ' that agrees well with tables in books. ' Should take a look at whether the "year" variable is needed at all -- probably not ' The calcs are based on the Lunde book, Solar Thermal Engineering.
Imports System.Math
Public Class SunCls
Public Const RadPerDeg As Single = 1 / 57.296
Public Const DegPerRad As Single = 57.296
Public Const Isc As Single = 429.0 ' Solar constant - solar inten at top of atmosphere BTU/hr-ft^2
' Constants used in solar calcs:
' Parameters used to estimate solar radiation intensity
' From Lunde table 3-2, pg 65
' Data is by month, jan index is 0, dec index is 11
Public ReadOnly DayNo() As Double = _
{19.85, 54.06, 80.0, 110.47, 140.15, 172.5, 201.84, 232.49, 265.0, 292.34, 324.2, 357.5}
Public ReadOnly Decl() As Double = _
{-20.0, -10.0, 0.0, 11.6, 20.0, 23.45, 20.6, 12.3, 0.0, -10.5, -19.8, -23.45}
Public ReadOnly A() As Double = _
{390, 385, 376, 360, 350, 345, 344, 351, 365, 378, 387, 391}
Public ReadOnly B() As Double = _
{0.142, 0.144, 0.156, 0.18, 0.196, 0.205, 0.207, 0.201, 0.177, 0.16, 0.149, 0.142}
Public ReadOnly C() As Double = _
{0.058, 0.06, 0.071, 0.097, 0.121, 0.134, 0.136, 0.122, 0.092, 0.073, 0.063, 0.057}
Public ReadOnly EqnT() As Double = _
{-11.2, -13.9, -7.5, 1.1, 3.3, -1.4, -6.2, -2.4, 7.5, 15, 4, 13.8, 1.6}
'Input vars
' Changing any of these vars requrires "recalc"
Private mDayOfMonth As Integer ' 1 to 31
Private mMonth As Integer ' 1 is jan, 2 feb ...
Private mYear As Integer ' the year - pick a non-leap year for default
Private mASTHr As Double ' Solar time, 12 is solar noon
Private mLongitude As Double ' Longitude -- West is + -- radians
Private mLatitude As Double ' Latitude -- + in NA -- radians
Private mAltitude As Double ' Altitude in ft
'Output vars
' All of the these vars are changed by a "recalc"
Private mDayOfYear As Integer ' day of the year
Private mHrAng As Double ' hour angle in radians, is measured from south, + to West (pm)
Private mDeclination As Double ' Declination - apparent angle of earths axis of rot to ecliptic
Private mZenithAng As Double ' The complement of the solar altitude -- i.e. 90 - AltAng radians
Private mAzimuthAng As Double ' Azimuth angle of sun -- measured from South, + to West
' NOTE this is + to West internally (to match Lunde book), but the
' property AzimuthAngle is reported as + to east (CCW about Z azis)
Private mAltAng As Double ' Solar altitude -- radians
Private mSunVec As New VectorCls ' A vector pointing toward sun (determined from AltAng and Azimuth
Private mIoext As Double ' solar radiation at top of atmosphere
Private mIdn As Double ' Direct normal radiation BTU/hr-ft^2
Private mIdiffuse As Double ' Diffuse radiation BTU/hr=ft^2
Private mItotal As Double ' Total solar radiation (Idn + Idiffuse)
Private mIHorz As Double ' Total solar radiation on horz surface
Private mSunRise As Double ' Hour of sunrise in solar time
Private mSunSet As Double ' Hour of sunset in solar time
Private UpToDate As Boolean
' Constructors
Sub New(ByVal Day As Integer, ByVal Month As Integer, ByVal Year As Integer, _
ByVal ASThr As Double, ByVal Longitude As Double, ByVal Latitude As Double, _
ByVal Altitude As Double)
mDayOfMonth = Day
mMonth = Month
mYear = Year
mASTHr = ASThr
mLongitude = Longitude
mLatitude = Latitude
mAltitude = Altitude
UpToDate = False
End Sub
Sub New()
mDayOfMonth = 21
mMonth = 12
mYear = 2003
mASTHr = 12
mLongitude = 0
mLatitude = 45 * RadPerDeg
mAltitude = 0
UpToDate = False
End Sub
' ---- Input Variable Gets and Sets for inputs
' ReCalc is called if any of these inputs are set
Public Property Year() As Integer
Get
Year = mYear
End Get
Set(ByVal Value As Integer)
mYear = Value
UpToDate = False
End Set
End Property
' Month number -- Jan = 1, ... Dec = 12
Public Property Month() As Integer
Get
Month = mMonth
End Get
Set(ByVal Value As Integer)
If (Value < 13) And (Value > 0) Then
mMonth = Value
UpToDate = False
End If
End Set
End Property
Public Property DayOfMonth() As Integer
Get
DayOfMonth = mDayOfMonth
End Get
Set(ByVal Value As Integer)
If (Value < 32) And (Value > 0) Then
mDayOfMonth = Value
UpToDate = False
End If
End Set
End Property
' ASThr -- solar time in hours -- 12hr = solar noon (sun is due south)
Public Property ASThr() As Double
Get
ASThr = mASTHr
End Get
Set(ByVal Value As Double)
mASTHr = Value
UpToDate = False
End Set
End Property
Public Property Longitude() As Double
Get
Longitude = mLongitude
End Get
Set(ByVal Value As Double)
mLongitude = Value
UpToDate = False
End Set
End Property
Public Property Latitude() As Double
Get
Latitude = mLatitude
End Get
Set(ByVal Value As Double)
mLatitude = Value
UpToDate = False
End Set
End Property
' Altitude above sea level in ft
Public Property Altitude() As Double
Get
Altitude = mAltitude
End Get
Set(ByVal Value As Double)
mAltitude = Value
UpToDate = False
End Set
End Property
' ---- Output Variable Gets ------------
' Hour Angle -- measured from South, + to East in radians (2 pi radians per day)
' NOTE: that internally HrAng is + to West, but this property is reported
' out as + to east (CCW about Z axis)
Public ReadOnly Property HrAng() As Double
Get
If Not UpToDate Then ReCalc()
HrAng = -mHrAng
End Get
End Property
' DayOfYear-- )
Public ReadOnly Property DayOfYear() As Double
Get
If Not UpToDate Then ReCalc()
DayOfYear = mDayOfYear
End Get
End Property
'Solar Declination angle (rad) -- apparent angle of earchs axis of rotation to Earth Sun line
' 23.45 deg at winter solstice, -23.45 at summer solstice, 0 at equinoxs
Public ReadOnly Property Declination() As Double
Get
If Not UpToDate Then ReCalc()
Declination = mDeclination
End Get
End Property
' Zenith Angle (rad) -- Is the complement of Altitude angle
Public ReadOnly Property ZenithAng() As Double
Get
If Not UpToDate Then ReCalc()
ZenithAng = mZenithAng
End Get
End Property
' Azimuth Angle (rad) -- Measure from South, + to East
' NOTE: that internally mAzimuthAngle is + to West, but this property is reported
' out as + to east (CCW about Z axis)
Public ReadOnly Property AzimuthAng() As Double
Get
If Not UpToDate Then ReCalc()
AzimuthAng = -mAzimuthAng
End Get
End Property
' Altitude Angle -- Elevation angle of sun (rad)
Public ReadOnly Property AltAng() As Double
Get
If Not UpToDate Then ReCalc()
AltAng = mAltAng
End Get
End Property
' ToSunVector -- a unit vector in the direction of the sun
' The Y comonpent of this vector is flipped to keep the convention
' + azimuth to East externally, and + az to West internally
Public ReadOnly Property ToSunVector() As VectorCls
Get
If Not UpToDate Then ReCalc()
Dim V As New VectorCls(mSunVec.X, -mSunVec.Y, mSunVec.Z)
ToSunVector = V
End Get
End Property
' Ioext -- solar radiation at top of atmosphere
Public ReadOnly Property Ioext() As Double
Get
If Not UpToDate Then ReCalc()
Ioext = mIoext
End Get
End Property
' Direct solar radiation -- (adjusted for date, altitude, and airmass) BTU/hr ft^2
Public ReadOnly Property Idn() As Double
Get
If Not UpToDate Then ReCalc()
Idn = mIdn
End Get
End Property
' Diffuse radiation -- BTU/hr ft^2
Public ReadOnly Property Idiffuse() As Double
Get
If Not UpToDate Then ReCalc()
Idiffuse = mIdiffuse
End Get
End Property
' Total solar radiation -- sum of Idn + Idiffuse BTU/hr ft^2
Public ReadOnly Property Itotal() As Double
Get
If Not UpToDate Then ReCalc()
Itotal = mItotal
End Get
End Property
' Total solar radiation on Horz Surface -- sum of Idn + Idiffuse BTU/hr ft^2
Public ReadOnly Property Ihorz() As Double
Get
If Not UpToDate Then ReCalc()
Ihorz = mIHorz
End Get
End Property
'Sunrise hour -- time of sunrise in solar time
Public ReadOnly Property Sunrise() As Double
Get
If Not UpToDate Then ReCalc()
Sunrise = mSunRise
End Get
End Property
' Sunset hour -- time of sunset in solar time
Public ReadOnly Property Sunset() As Double
Get
If Not UpToDate Then ReCalc()
Sunset = mSunSet
End Get
End Property
' ReCalc -- this routine must be called after any of the input vars in changed by user.
' It recalculates all of the output solar parameters to agree with current inputs
' The calculations are based on the book "Solar Thermal Engineering", Lunde
Public Sub ReCalc()
UpToDate = True ' moved this here to prevent recursive calls to ReCalc
' Day of Year
Dim mDate As Date
mDate = DateSerial(mYear, mMonth, mDayOfMonth)
mDayOfYear = mDate.DayOfYear
' Ioext is solar radiation at top of atmosphere --
' it is based on the solar constant corrected for earth to sun distance
mIoext = Isc * (1 + 0.033 * Cos((360 * mDayOfYear / 370.0) * RadPerDeg))
' Declination -- The apparent tilt of the earths axis of rotation to the ecliptic
' +23.45 at summer solstice, -23.45 at winter solstice, and 0 at the equinoxes
' returns declination for the day of year in radians
mDeclination = RadPerDeg * 23.45 * Sin(((mDayOfYear - 80) / 370) * 360 * RadPerDeg)
'Hour Angle --
' found by taking the time between solar noon and current AST, and
' multiplying by 15 deg/hr, then converting to radians.
mHrAng = (mASTHr - 12.0) * (360 / 24) * RadPerDeg
' Altitude Angle -- the solar altitude in radians
mAltAng = Asin(Cos(mLatitude) * Cos(mDeclination) * Cos(mHrAng) _
+ Sin(mLatitude) * Sin(mDeclination))
' Zenith Angle
mZenithAng = 90 * RadPerDeg - mAltAng
' Solar Azimuth -- angle of sun from due south in radians -- + to west
' this is the one that is dual valued
' Solar Azimuth -- angle of sun from due south in radians -- + to west
' this is the one that is dual valued
Dim sinAzAng As Single = Cos(mDeclination) * Sin(mHrAng) / Cos(mAltAng)
mAzimuthAng = Asin(sinAzAng)
' Alt at azimuth of 90
Dim alt90 As Double
alt90 = Asin(Sin(mDeclination) / Sin(mLatitude))
' if the sun higher than alt90, then mAzimuth is ok, else is 180 - mAz
If (mAltAng < alt90) Then
If mAzimuthAng < 0 Then
mAzimuthAng = -180 * RadPerDeg - mAzimuthAng
Else
mAzimuthAng = 180 * RadPerDeg - mAzimuthAng
End If
End If
' Calc the ToSun Vector
mSunVec = VectorCls.AzElevVector(mAzimuthAng, mAltAng)
' Direct Normal Irradiation -- in BTU/hr - ft^2
' This is direct normal irradation on sunny day corrected for air mass and
' for altitude
Dim A, B As Double
Dim Palt_to_Psl As Double
Palt_to_Psl = Exp(-0.0000361 * mAltitude)
A = Aparm()
B = Bparm()
' Check for nightime
If mAltAng > 0 Then
mIdn = A * Exp(-Palt_to_Psl * B / Cos(mZenithAng))
Else
mIdn = 0
End If
' Diffuse solar radiantion
' Calced as table factor "C" times the direct normal
Dim C As Double
C = Cparm()
mIdiffuse = Idn() * Cparm()
' Toal solar radiation -- is sum of direct normal (Idn) and diffuse (Idiffuse)
' BTU/hr - ft^2
mItotal = mIdn + mIdiffuse
' Total radiation radiation on Horz surface
mIHorz = mIdn * Sin(mAltAng) + mIdiffuse
' Sunrise hour
Dim SRHourAng As Double
SRHourAng = Acos(-Tan(mLatitude) * Tan(mDeclination))
mSunRise = 12.0 - SRHourAng / (15 * RadPerDeg)
mSunSet = 12.0 + SRHourAng / (15 * RadPerDeg)
End Sub ' ReCalc
' interpolations for A as function of day of year
' these routines are called by ReCalc to get interpolated values for
' the parms in the table
Friend Function Aparm() As Double
Dim H, L As Double
Dim frac As Double
If (mDayOfYear < 19.85) Then
L = 391
H = 390
frac = mDayOfYear / 19.85
ElseIf (mDayOfYear >= 357) Then
L = 391
H = 391
frac = 0
Else
Dim i As Integer = 0
While (mDayOfYear > DayNo(i))
i = i + 1
End While
L = A(i - 1)
H = A(i)
frac = (mDayOfYear - DayNo(i - 1)) / (DayNo(i) - DayNo(i - 1))
End If
Aparm = L + (H - L) * frac
End Function
' interpolations for B as function of day of year
' B is Air Mass factor from the B array above
Friend Function Bparm() As Double
Dim H, L As Double
Dim frac As Double
If (mDayOfYear < 19.85) Then
L = 0.142
H = 0.142
frac = 0
ElseIf (mDayOfYear > 357) Then
L = 0.142
H = 0.142
frac = 0
Else
Dim i As Integer = 0
While (mDayOfYear > DayNo(i))
i = i + 1
End While
L = B(i - 1)
H = B(i)
frac = (mDayOfYear - DayNo(i - 1)) / (DayNo(i) - DayNo(i - 1))
End If
Bparm = L + (H - L) * frac
End Function
' interpolations for C as function of day of year
' C is a factor from the C array above
Friend Function Cparm() As Double
Dim H, L As Double
Dim frac As Double
If (mDayOfYear < 19.85) Then
L = 0.058
H = 0.057
frac = mDayOfYear / 19.85
ElseIf (mDayOfYear > 357) Then
L = 0.057
H = 0.057
frac = 0
Else
Dim i As Integer = 0
While (mDayOfYear > DayNo(i))
i = i + 1
End While
L = C(i - 1)
H = C(i)
frac = (mDayOfYear - DayNo(i - 1)) / (DayNo(i) - DayNo(i - 1))
End If
Cparm = L + (H - L) * frac
End Function
' interpolations for Equation of Time as function of day of year
Friend Function EqnTparm() As Double
Dim H, L As Double
Dim frac As Double
If (mDayOfYear < 19.85) Then
L = 1.6
H = -11.2
frac = mDayOfYear / 19.85
ElseIf (mDayOfYear > 357) Then
L = 1.6
H = 1.6
frac = 0
Else
Dim i As Integer = 0
While (mDayOfYear > DayNo(i))
i = i + 1
End While
L = EqnT(i - 1)
H = EqnT(i)
frac = (mDayOfYear - DayNo(i - 1)) / (DayNo(i) - DayNo(i - 1))
End If
EqnTparm = L + (H - L) * frac
End Function
Public Sub Dump()
If Not UpToDate Then ReCalc()
Console.WriteLine("Sun Object:")
Console.WriteLine("Date, DayOfYr {0,2} {1,2} {2,4} DOY {3,4}", Month, DayOfMonth, Year, DayOfYear) ' As Integer = 21 ' 1 to 31
Console.WriteLine("ASThr {0,4:F1}", ASThr) ' As Double = 12.0 ' Solar time, 12 is solar noon
Console.WriteLine("Long, Lat, Altitude {0,4:F1} {1,4:F1} {2,4:F1}", _
Longitude * DegPerRad, Latitude * DegPerRad, Altitude) ' As Double = 111.0 * RadPerDeg ' Longitude -- West is + -- radians
'Output vars
' All of the these vars are changed by a "recalc"
Console.WriteLine("Declination, HrAngle {0,4:F1} {1,4:F1}", Declination * DegPerRad, HrAng * DegPerRad) ' hour angle in radians, is measured from south, + to West (pm)
Console.WriteLine("Azimuth, Altitude {0,5:F1} {1,5:F1}", AzimuthAng * DegPerRad, AltAng * DegPerRad) ' Azimuth angle of sun -- measured from South, + to West internally,
' but reported out as + to East
Console.WriteLine("ToSunVec X,Y,Z {0,6:F3} {1,6:F3} {2,6:F3}", ToSunVector.X, ToSunVector.Y, ToSunVector.Z) ' to sun vector
Console.WriteLine("Ioext {0,6:F1}", Ioext) ' solar radiation at top of atmosphere
Console.WriteLine("Idn, Idif, Itot {0,6:F1} {1,6:F1} {2,6:F1}", Idn, Idiffuse, Itotal) ' Direct normal radiation BTU/hr-ft^2
Console.WriteLine("Ihorz {0,6:F1}", Ihorz) ' Total solar radiation on horz surface
Console.WriteLine("SunRise, Sunset {0,4:F1} {1,4:F1}", Sunrise, Sunset) ' Hour of sunrise in solar time
End Sub
End Class ' sun