Exemple #1
0
        // Calculate manages calculations that need to be run for each time step
        public void Calculate
        (
            double PanelTilt                        // The angle between the surface tilt of the module and the ground [radians]
            , double Clearance                      // Array ground clearance [m]
            , double HDif                           // Diffuse horizontal irradiance [W/m2]
            , double TDifRef                        // Front reflected diffuse irradiance [W/m2]
            , double HGlo                           // Horizontal global irradiance [W/m2]
            , double[] frontGroundGHI               // Global irradiance for each of the ground segments to front of the row [W/m2]
            , double[] rearGroundGHI                // Global irradiance for each of the ground segments to rear of the row [W/m2]
            , double aveGroundGHI                   // Average global irradiance on ground segment to the rear of row [W/m2]
            , int month                             // Current month, used for getting albedo value [#]
            , double backSH                         // Fraction of the back surface of the PV array that is unshaded [#]
            , double TDir                           // Back tilted beam irradiance [W/m2]
            , DateTime ts                           // Time stamp analyzed, used for printing .csv files
        )
        {
            // For tracking systems, panel tilt and ground clearance will change at each time step
            itsPanelTilt = PanelTilt;
            itsClearance = Clearance / itsArrayBW;           // Convert to panel slope lengths

            int numGroundSegs = Util.NUM_GROUND_SEGS;

            double h = Math.Sin(itsPanelTilt);               // Vertical height of sloped PV panel [panel slope lengths]
            double b = Math.Cos(itsPanelTilt);               // Horizontal distance from front of panel to back of panel [panel slope lengths]

            // Calculate x, y coordinates of bottom and top edges of PV row behind the current PV row so that portions of sky and ground viewed by
            // the PV cell may be determined. Coordinates are relative to (0,0) being the ground point below the lower front edge of current PV row.
            // The row behind the current row is in the positive x direction.
            double bottomX = itsPitch;                       // x value for point on bottom edge of PV panel behind current row
            double bottomY = itsClearance;                   // y value for point on bottom edge of PV panel behind current row
            double topX    = bottomX + b;                    // x value for point on top edge of PV panel behind current row
            double topY    = bottomY + h;                    // y value for point on top edge of PV panel behind current row

            // Get albedo value for the month
            Albedo = itsMonthlyAlbedo[month];

            // Accumulate diffuse, reflected, and beam irradiance components for each cell row over its field of view of PI radians
            for (int i = 0; i < numCellRows; i++)
            {
                double cellX = b * (i + 0.5) / numCellRows;                                     // x value for location of cell
                double cellY = itsClearance + h * (i + 0.5) / numCellRows;                      // y value for location of cell

                double elevUp   = 0.0;                                                          // Elevation angle from PV cell to top of PV panel
                double elevDown = 0.0;                                                          // Elevation angle from PV cell to bottom of PV panel
                if (itsRowType == RowType.INTERIOR)
                {
                    elevUp   = Math.Atan((topY - cellY) / (topX - cellX));
                    elevDown = Math.Atan((cellY - bottomY) / (bottomX - cellX));
                }

                int stopSky     = Convert.ToInt32((itsPanelTilt - elevUp) * Util.RTOD);         // Last whole degree in arc range that sees sky; first is 0 [degrees]
                int startGround = Convert.ToInt32((itsPanelTilt + elevDown) * Util.RTOD);       // First whole degree in arc range that sees ground; last is 180 [degrees]

                // Compute sky diffuse component
                backDif[i] = RadiationProc.GetViewFactor(0, stopSky * Util.DTOR) * HDif;

                // Compute front surface reflected component
                if (itsRowType == RowType.INTERIOR)
                {
                    backFroRef[i] = RadiationProc.GetViewFactor(stopSky * Util.DTOR, startGround * Util.DTOR) * TDifRef;
                }

                backGroRef[i] = 0;
                // Add ground reflected component
                for (int j = startGround; j < 180; j++)
                {
                    // Get start and ending elevations for this (j, j + 1) pair
                    double startElevDown = elevDown + (j - startGround) * Util.DTOR;
                    double stopElevDown  = elevDown + (j + 1 - startGround) * Util.DTOR;

                    // Projection onto ground in positive x direction
                    double projX2 = cellX + cellY / Math.Tan(startElevDown);
                    double projX1 = cellX + cellY / Math.Tan(stopElevDown);

                    // Initialize and get actualGroundGHI value
                    double actualGroundGHI = 0;
                    if (Math.Abs(projX1 - projX2) > 0.99 * itsPitch)
                    {
                        if (itsRowType == RowType.SINGLE)
                        {
                            // Use measured GHI if projection approximates or exceeds the pitch
                            actualGroundGHI = HGlo;
                        }
                        else
                        {
                            // Use average GHI if projection approximates or exceeds the pitch
                            actualGroundGHI = aveGroundGHI;
                        }
                    }
                    else
                    {
                        // Normalize projections and multiply by n
                        projX1 = numGroundSegs * projX1 / itsPitch;
                        projX2 = numGroundSegs * projX2 / itsPitch;

                        if (itsRowType == RowType.SINGLE && ((Math.Abs(projX1) > numGroundSegs - 1) || (Math.Abs(projX2) > numGroundSegs - 1)))
                        {
                            // Use measured GHI if projection exceeds the pitch
                            actualGroundGHI = HGlo;
                        }
                        else
                        {
                            while (projX1 < -numGroundSegs || projX2 < -numGroundSegs)
                            {
                                projX1 += numGroundSegs;
                                projX2 += numGroundSegs;
                            }
                            while (projX1 >= numGroundSegs || projX2 >= numGroundSegs)
                            {
                                projX1 -= numGroundSegs;
                                projX2 -= numGroundSegs;
                            }

                            // Determine indices (truncate values) for use with groundGHI arrays
                            int index1 = Convert.ToInt32(Math.Floor(projX1 + numGroundSegs) - numGroundSegs);
                            int index2 = Convert.ToInt32(Math.Floor(projX2 + numGroundSegs) - numGroundSegs);

                            if (index1 == index2)
                            {
                                // Use single value if projection falls within a single segment of ground
                                if (index1 < 0)
                                {
                                    actualGroundGHI = frontGroundGHI[index1 + numGroundSegs];
                                }
                                else
                                {
                                    actualGroundGHI = rearGroundGHI[index1];
                                }
                            }
                            else
                            {
                                // Sum the irradiances on the ground if the projection falls across multiple segments
                                for (int k = index1; k <= index2; k++)
                                {
                                    if (k == index1)
                                    {
                                        if (k < 0)
                                        {
                                            actualGroundGHI += frontGroundGHI[k + numGroundSegs] * (k + 1.0 - projX1);
                                        }
                                        else
                                        {
                                            actualGroundGHI += rearGroundGHI[k] * (k + 1.0 - projX1);
                                        }
                                    }
                                    else if (k == index2)
                                    {
                                        if (k < 0)
                                        {
                                            actualGroundGHI += frontGroundGHI[k + numGroundSegs] * (projX2 - k);
                                        }
                                        else
                                        {
                                            actualGroundGHI += rearGroundGHI[k] * (projX2 - k);
                                        }
                                    }
                                    else
                                    {
                                        if (k < 0)
                                        {
                                            actualGroundGHI += frontGroundGHI[k + numGroundSegs];
                                        }
                                        else
                                        {
                                            actualGroundGHI += rearGroundGHI[k];
                                        }
                                    }
                                }
                                // Get irradiance on ground in the 1 degree field of view
                                actualGroundGHI /= projX2 - projX1;
                            }
                        }
                    }
                    backGroRef[i] += RadiationProc.GetViewFactor(j * Util.DTOR, (j + 1) * Util.DTOR) * actualGroundGHI * Albedo;
                }

                double cellShade = 0.0;
                if (itsRowType == RowType.INTERIOR)
                {
                    // Cell is fully shaded if >= 1, fully unshaded if <= 0, otherwise fractionally shaded
                    cellShade = (1.0 - backSH) * numCellRows - i;
                    cellShade = Math.Min(cellShade, 1.0);
                    cellShade = Math.Max(cellShade, 0.0);
                }

                // Compute beam component, corrected for back shading
                backDir[i] = TDir * (1.0 - cellShade);

                // Correct each component for AOI and structure shading losses
                backDif[i]    = backDif[i] * IAMDif * (1.0 - structLossFactor);
                backFroRef[i] = backFroRef[i] * IAMRef * (1.0 - structLossFactor);
                backGroRef[i] = backGroRef[i] * IAMRef * (1.0 - structLossFactor);
                backDir[i]    = backDir[i] * IAMDir * (1.0 - structLossFactor);

                // Sum all components to get global back irradiance
                backGlo[i] = backDif[i] + backFroRef[i] + backGroRef[i] + backDir[i];
            }

            BDif    = 0;
            BFroRef = 0;
            BGroRef = 0;
            BDir    = 0;

            double maxGlo = backGlo[0];
            double minGlo = backGlo[0];

            for (int i = 0; i < numCellRows; i++)
            {
                // Calculate mean irradiance components
                BDif    += backDif[i] / numCellRows;
                BFroRef += backFroRef[i] / numCellRows;
                BGroRef += backGroRef[i] / numCellRows;
                BDir    += backDir[i] / numCellRows;

                // Find the max and min global irradiance values
                maxGlo = Math.Max(maxGlo, backGlo[i]);
                minGlo = Math.Min(minGlo, backGlo[i]);
            }
            BGlo = BDif + BFroRef + BGroRef + BDir;

            // Calculate the homogeneity of values as the range normalized by the sum
            IrrInhomogeneity = (BGlo > 0) ? (maxGlo - minGlo) / BGlo : 0;

            // Option to print details of the model in .csv files. Only recommended for single day simulations.
            // PrintModel(ts);
        }
Exemple #2
0
        double CalcSkyViewDirection
        (
            double x                                            // Horizontal dimension in the row-to-row ground area
            , RowType rowType                                   // The position of the row being calculated relative to others [unitless]
            , double direction                                  // The direction in which to move along the x-axis [-1, 0, 1]
        )
        {
            double h = Math.Sin(itsPanelTilt);                  // Vertical height of sloped PV panel [panel slope lengths]
            double b = Math.Cos(itsPanelTilt);                  // Horizontal distance from front of panel to back of panel [panel slope lengths]

            double offset   = direction;                        // Initialize offset to begin at first unit of given direction
            double skyPatch = 0;                                // View factor for view of sky in single row-to-row area
            double skySum   = 0;                                // View factor for all sky views in given direction

            double angA  = 0;
            double angB  = 0;
            double angC  = 0;
            double angD  = 0;
            double beta1 = 0;                                   // Start of ground's field of view that sees the sky segment
            double beta2 = 0;                                   // End of ground's field of view that sees the sky segment

            // Sum sky view factors until sky view factor contributes <= 1% of sum
            // Only loop the calculation for rows extending forward or backward, so break loop when direction = 0.
            do
            {
                // Set back limiting angle to 0 since there is no row behind.
                if (rowType == RowType.LAST)
                {
                    beta1 = 0;
                }
                else
                {
                    // Angle from ground point to top of panel P
                    angA = Math.Atan2(h + itsClearance, (offset + 1) * itsPitch + b - x);
                    // Angle from ground point to bottom of panel P
                    angB = Math.Atan2(itsClearance, (offset + 1) * itsPitch - x);

                    beta1 = Math.Max(angA, angB);
                }

                // Set front limiting angle to PI since there is no row ahead.
                if (rowType == RowType.FIRST)
                {
                    beta2 = Math.PI;
                }
                else
                {
                    // Angle from ground point to top of panel Q
                    angC = Math.Atan2(h + itsClearance, offset * itsPitch + b - x);
                    // Angle from ground point to bottom of panel Q
                    angD = Math.Atan2(itsClearance, offset * itsPitch - x);

                    beta2 = Math.Min(angC, angD);
                }

                // If there is an opening in the sky through which the sun is seen, calculate view factor of sky patch
                skyPatch = (beta2 > beta1) ? RadiationProc.GetViewFactor(beta1, beta2) : 0;

                skySum += skyPatch;
                offset += direction;
            } while (offset != 0 && skyPatch > (0.01 * skySum));

            return(skySum);
        }