Beispiel #1
0
        // Compute apparent sunset on a titled surface facing the equator
        // Duffie and Beckman (1991) eqn 2.19.3b
        public static double GetApparentSunsetHourAngleEquator // (o) apparent sunset hour angle [radians]
            (double Slope                                      // (i) slope of receiving surface [radians]
            , double Lat                                       // (i) latitude [radians, N > 0]
            , double Decl                                      // (i) declination [radians]
            )
        {
            double IsNorth, Aux1, Aux2;

            IsNorth = (Lat > 0) ? 1 : -1;
            Aux1    = Astro.GetSunsetHourAngle(Lat, Decl);
            Aux2    = Astro.GetSunsetHourAngle(Lat - IsNorth * Slope, Decl);
            return(Math.Min(Aux1, Aux2));
        }
Beispiel #2
0
        // Compute apparent sunrise and sunset times on a tilted surface of any orientation
        // Duffie and Beckman (1991) eqn 2.20.5e to 2.20.5i
        public static void CalcApparentSunsetHourAngle
            (double Lat                               // (i) latitude [radians]
            , double Decl                             // (i) declination [radians]
            , double Slope                            // (i) slope of receiving surface [radians]
            , double Azimuth                          // (i) azimuth angle of receiving surface [radians]
            , out double AppSunrise                   // (o) apparent sunrise hour angle [radians]
            , out double AppSunset                    // (o) apparent sunset hour angle [radians]
            , out double Sunset                       // (o) true sunset hour angle [radians]
            )
        {
            // Declarations
            double aux1, aux2, aux3, disc;
            double cosInc, SunZenith, SunAzimuth;
            double A, B, C;

            // Calculate true sunset and parameters A, B and C
            Sunset = Astro.GetSunsetHourAngle(Lat, Decl);
            A      = Math.Cos(Slope) + Math.Tan(Lat) * Math.Cos(Azimuth) * Math.Sin(Slope);
            B      = Math.Cos(Sunset) * Math.Cos(Slope) + Math.Tan(Decl) * Math.Sin(Slope) * Math.Cos(Azimuth);
            C      = Math.Sin(Slope) * Math.Sin(Azimuth) / Math.Cos(Lat);

            // Pathological case: the sun does not rise
            if (Sunset == 0)
            {
                AppSunrise = AppSunset = 0;
                return;
            }

            // Normal case
            aux1 = A * A + C * C;
            disc = aux1 - B * B;

            // Check discriminant. If it is positive or zero, the sun rises (tangentially)
            // on the surface. In that case, calculate apparent sunrise and apparent
            // sunset
            if (disc >= 0)
            {
                aux2       = C * Math.Sqrt(disc) / aux1;
                aux3       = A * B / aux1;
                AppSunrise = Math.Min(Sunset, Math.Acos(aux3 + aux2));
                AppSunset  = Math.Min(Sunset, Math.Acos(aux3 - aux2));
                if ((A > 0 && B > 0) || (A >= B))
                {
                    AppSunrise = -AppSunrise;
                }
                else
                {
                    AppSunset = -AppSunset;
                }
            }

            // If discriminant is negative, the surface is either always or never
            // illuminated during the day. To find which case applies, compute the
            // cosine of the angle of incidence on the surface at noon. If it is less
            // than zero, then the surface is always in the dark. If it is greater
            // than zero, then the surface is always illuminated
            else
            {
                Astro.CalcSunPositionHourAngle(Decl, 0, Lat, out SunZenith, out SunAzimuth);
                cosInc = GetCosIncidenceAngle(SunZenith, SunAzimuth, Slope, Azimuth);
                if (cosInc < 0)
                {
                    AppSunrise = AppSunset = 0;
                }
                else
                {
                    AppSunrise = -Sunset;
                    AppSunset  = Sunset;
                }
            }
        }
Beispiel #3
0
        // Calculation method
        // There are 6 ways to call the Calculate method; for each, only some of the parameters are required to calculate global, beam and diffuse. The inputs can be
        // 1. global horizontal
        // 2. global horizontal and diffuse horizontal
        // 3. global horizontal and direct horizontal
        // 4. global horizontal and direct normal
        // 5. diffuse horizontal and direct horizontal
        // 6. diffuse horizontal and direct normal
        public void Calculate
        (
            double Zenith                   // zenith angle of sun [radians]
            , double _HGlo  = double.NaN    // global horizontal irradiance [W/m2]
            , double _HDif  = double.NaN    // diffuse horizontal irradiance [W/m2]
            , double _NDir  = double.NaN    // direct normal irradiance [W/m2]
            , double _HDir  = double.NaN    // direct horizontal irradiance [W/m2]
            , double NExtra = double.NaN    // normal extraterrestrial irradiance [W/m2]
        )
        {
            // Set all values to an invalid
            // Check that at least some of the radiation inputs are properly defined
            try
            {
                // Either HGlo has to be defined, or HDif and one of the two direct components
                if (double.IsNaN(_HGlo) && (double.IsNaN(_HDif) || (double.IsNaN(HDir) && double.IsNaN(NDir))))
                {
                    throw new CASSYSException("Splitter: insufficient number of inputs defined.");
                }

                // If global is defined, cannot have both diffuse and direct defined
                if (!double.IsNaN(_HGlo) && !double.IsNaN(_HDif) && ((!double.IsNaN(_HDir)) || !double.IsNaN(_NDir)))
                {
                    throw new CASSYSException("Splitter: cannot specify both diffuse and direct when global is used.");
                }

                // Cannot have direct normal and direct horizontal defined
                if (!double.IsNaN(_HDir) && !double.IsNaN(_NDir))
                {
                    throw new CASSYSException("Splitter: cannot specify both direct normal and direct horizontal.");
                }

                // If global is defined but neither diffuse and direct are defined,
                // then additional inputs are required to calculate them
                if (!double.IsNaN(_HGlo) && !double.IsNaN(_HDif) && !double.IsNaN(_HDir) && !double.IsNaN(_NDir))
                {
                    if (NExtra == double.NaN)
                    {
                        throw new CASSYSException("Splitter: Extraterrestrial irradiance is required when only global horizontal is specified.");
                    }
                }
            }
            catch (CASSYSException cs)
            {
                ErrorLogger.Log(cs, ErrLevel.FATAL);
            }

            // Calculate cos of zenith angle
            double cosZ = Math.Cos(Zenith);

            // First case: only global horizontal is defined
            // Calculate diffuse using the Hollands and Orgill correlation
            try
            {
                // If only HGlo is specified this case is used, first check the values provided in the program:
                if (!double.IsNaN(_HGlo) && double.IsNaN(_HDif) && double.IsNaN(_NDir) && double.IsNaN(_HDir))
                {
                    // Initialize value of HGlo
                    HGlo = _HGlo;

                    // If sun below horizon, direct is zero and diffuse is global
                    // Changed this to sun below 87.5° as high zenith angles sometimes caused problems of
                    // high direct on tilted surfaces
                    if (Zenith > 87.5 * DTOR || HGlo <= 0)
                    {
                        HDif = HGlo;
                        HDir = NDir = 0;
                    }

                    // Compute diffuse fraction
                    else
                    {
                        double kt = Sun.GetClearnessIndex(HGlo, NExtra, Zenith);
                        double kd = Sun.GetDiffuseFraction(kt);
                        kd = Math.Min(kd, 1.0);
                        kd = Math.Max(kd, 0.0);

                        // Compute diffuse and direct on horizontal
                        HDif = HGlo * kd;
                        HDir = HGlo - HDif;
                        NDir = HDir / cosZ;
                    }

                    // Limit beam normal to clear sky value
                    // ASHRAE clear sky model (ASHRAE Handbook - Fundamentals, 2013, ch. 14) with tau_b = 0.245, taud = 2.611, a_b = 0.668 and a_d = 0.227
                    // (these values are from Flagstaff, AZ, for the month of June, and lead to one of the highest beam/extraterrestrial ratios worldwide)
                    double AirMass = Astro.GetAirMass(Zenith);
                    double NDir_cs = NExtra * Math.Exp(-0.245 * Math.Pow(AirMass, 0.668));
                    NDir = Math.Min(NDir, NDir_cs);
                    HDir = NDir * cosZ;
                    HDif = HGlo - HDir;
                }

                // Second case: global horizontal and diffuse horizontal are defined then this
                else if (_HGlo != double.NaN && _HDif != double.NaN)
                {
                    // If sun below horizon, direct is zero and diffuse is global
                    // Changed this to sun below 87.5° as high zenith angles sometimes caused problems of
                    // high direct on tilted surfaces
                    if (Zenith > 87.5 * DTOR || _HGlo <= 0)
                    {
                        HGlo = _HGlo;
                        HDif = _HGlo;
                        HDir = NDir = 0;
                    }
                    else
                    {
                        HGlo = _HGlo;
                        HDif = Math.Min(_HGlo, _HDif);
                        HDir = HGlo - HDif;
                        NDir = HDir / cosZ;
                    }
                }

                // Third case: global horizontal and direct horizontal are defined
                else if (_HGlo != double.NaN && _HDir != double.NaN)
                {
                    HGlo = _HGlo;
                    HDir = Math.Min(_HGlo, _HDir);
                    HDif = HGlo - HDir;
                    NDir = HDir / cosZ;
                }

                // Fourth case: global horizontal and direct normal are defined
                else if (_HGlo != double.NaN && _NDir != double.NaN)
                {
                    HGlo = _HGlo;
                    HDir = Math.Min(HGlo, NDir * cosZ);
                    HDif = HGlo - HDir;
                    NDir = HDir / cosZ;
                }

                // Fifth case: diffuse horizontal and direct horizontal are defined
                else if (_HDif != double.NaN && _HDir != double.NaN)
                {
                    HDif = _HDif;
                    HDir = _HDir;
                    HGlo = HDif + HDir;
                    NDir = HDir / cosZ;
                }

                // Sixth case: diffuse horizontal and direct normal are defined
                else if (_HDif != double.NaN && _NDir != double.NaN)
                {
                    HDif = _HDif;
                    NDir = _NDir;
                    HDir = NDir * cosZ;
                    HGlo = HDif + HDir;
                }

                // Other cases: should never get there
                else
                {
                    throw new CASSYSException("Splitter: unexpected case encountered.");
                }
            }
            catch (CASSYSException ex)
            {
                ErrorLogger.Log(ex, ErrLevel.FATAL);
            }
        }
Beispiel #4
0
        // Calculation for inverter output power, using efficiency curve
        public void Calculate
        (
            int DayOfYear                             // Day of year (1-365)
            , double Hour                             // Hour of day, in decimal format (11.75 = 11:45 a.m.)
        )
        {
            double itsSLatR  = Utilities.ConvertDtoR(itsSLat);
            double itsSLongR = Utilities.ConvertDtoR(itsSLong);
            double itsMLongR = Utilities.ConvertDtoR(itsMLong);

            try
            {
                if (DayOfYear < 1 || DayOfYear > 365 || Hour < 0 || Hour > 24)
                {
                    throw new CASSYSException("Sun.Calculate: Invalid time stamp for sun position calculation");
                }
            }
            catch (CASSYSException cs)
            {
                ErrorLogger.Log(cs, ErrLevel.FATAL);
            }

            // Compute declination and normal extraterrestrial Irradiance if day has changed
            // Compute Sunrise and Sunset hour angles
            if (DayOfYear != itsCurrentDayOfYear)
            {
                itsCurrentDayOfYear = DayOfYear;
                itsCurrentDecl      = Astro.GetDeclination(itsCurrentDayOfYear);
                itsCurrentNExtra    = Astro.GetNormExtra(itsCurrentDayOfYear);

                // Variables used to hold the apparent/true sunset and sunrise hour angles
                double appSunRiseHA;                        // Hour angle for Sunrise [radians]
                double appSunsetHA;                         // Hour angle for Sunset  [radians]
                double trueSunsetHA;                        // True Sunset Hour angle [radians]

                // Invoking the Tilt method to get the values
                Tilt.CalcApparentSunsetHourAngle(itsSLatR, itsCurrentDecl, itsSurfaceSlope, Azimuth, out appSunRiseHA, out appSunsetHA, out trueSunsetHA);

                // Assigning to the output values
                AppSunriseHour  = Math.Abs(appSunRiseHA) * Util.HAtoR;
                AppSunsetHour   = Util.NoonHour + appSunsetHA * Util.HAtoR;
                TrueSunSetHour  = Util.NoonHour + trueSunsetHA * Util.HAtoR;
                TrueSunRiseHour = TrueSunSetHour - Astro.GetDayLength(itsSLatR, itsCurrentDecl);

                // If using local standard time then modify the sunrise and sunset to match the local time stamp.
                if (itsLSTFlag)
                {
                    TrueSunSetHour -= Astro.GetATmsST(DayOfYear, itsSLongR, itsMLongR) / 60; // Going from solar to local time
                    TrueSunRiseHour = TrueSunSetHour - Astro.GetDayLength(itsSLatR, itsCurrentDecl);
                }
            }

            // Compute hour angle
            double SolarTime = Hour;

            if (itsLSTFlag)
            {
                SolarTime += Astro.GetATmsST(DayOfYear, itsSLongR, itsMLongR) / 60; // Going from local to solar time
            }

            double HourAngle = Astro.GetHourAngle(SolarTime);

            // Compute azimuth and zenith angles
            Astro.CalcSunPositionHourAngle(itsCurrentDecl, HourAngle, itsSLatR, out Zenith, out Azimuth);

            // Compute normal extraterrestrial Irradiance
            NExtra = itsCurrentNExtra;

            // Compute air mass
            AirMass = Astro.GetAirMass(Zenith);
        }