Assignment #06

Unit 06

Until next week, work through the material provided in Unit 6 and solve the following exercises.

This week, we have two main objectives. First, we want to create our own python module solar that contains a number of useful functions related to analyzing solar radiation data. Second, we want to apply the functionality provided by our solar module to some photovoltaic questions. Overall, this assignment will give you the opportunity to work on your skills in writing and applying own functions, creating and working with a DataFrame with datetime index, manipulating data, and plotting it using different plot types as well as creating quick n’ dirty and polished figures.

Radiation onto a tilted surface

The declination \(\delta\) is the angular measure of the sun’s position relative to our equator, changing throughout the year as Earth orbits the sun. It is a function of the day of year \(n\): \[ \delta = \epsilon \cdot sin(2\pi \cdot \frac{n-80}{365})\] where \(\epsilon = 23.45 ^\circ\) is the obliquity of the ecliptic.

The hour angle \(\tau\) is the measure of time since solar noon, expressed in angular units, indicating the position of the sun in the sky relative to the observer’s meridian. At noon true local time, \(\tau = 0\), it is negative in the morning and postive in the afternoon. To compute the hour angle (in degrees) from an actual time, we first calculate local solar time (LST), here starting off of UTC: \[t_{LST} = t_{UTC} + \frac{\lambda}{15}\] where \(t_{UTC}\) and \(t_{LST}\) are the wall times in UTC and local solar time, respectively. \(\lambda\) is the geographical longitude. In Dornbirn, \(\lambda = 9.7438 ^\circ\).

Then, local solar time can be converted to angular values by \[\tau = 15 \cdot (t_{LST} - 12)\] To make the resulting sign of \(\tau\) fall into the convention mentioned above, all values of \(\tau > 180\) need to be subtracted with \(360\).

The elevation angle \(h\) of the sun represents its apparent height above the observer’s horizon, with \(90 ^\circ\) denoting directly overhead and \(0 ^\circ\) at the horizon. We computed it during Workshop 1, and use the same formula in a slightly rearranged format: \[h = arcsin(cos(\delta) \cdot cos(\tau) \cdot cos(\varphi) + sin(\delta) \cdot sin(\varphi))\] where \(\varphi\) is the geographical latitude, again in Dornbirn \(\varphi = 47.4124 ^\circ\).

The solar azimuth \(\alpha\) represents the horizontal direction of the sun from an observer’s location. While in meteorology and navigation the azimuth is usually measured clockwise from north, in astronomy the solar azimuth \(\alpha = 0\) when the sun is in the south. \[ \alpha = arccos(\frac{sin(h)\cdot sin(\varphi) - sin(\delta)}{cos(h)\cdot cos(\varphi)})\]

Due to the \(arccos\) function, the computation of morning/afternoon angles is ambiguous. We can eliminate the problem by multiplying \(\alpha\) with the sign of \(\tau\) (remember that \(\tau\) was negative in the morning, and positive in the afternoon). This, however, changes the angle representation to negative values in the East, and postive ones in the West. To bring our angle format back to the convention (\(0\) in the South increasing clockwise to \(360 ^\circ\)), we add \(360 ^\circ\) and then take the modulo to ensure that no values are \(> 360 ^\circ\). To sum up, we modify \(\alpha\) from the formula above by \[\alpha = (\alpha \cdot \text{signum}(\tau) + 360) \bmod 360\]

The incidence angle \(\theta\) describes the angle between the direction of the direct sun light and the normal (perpendicular) to the surface of interest (i.e., the actual horizontal surface, or in our case a tilted PV module). This angle impacts the efficiency of energy absorption. \[cos(\theta) = cos(\beta_{PV}) \cdot sin(h) + sin(\beta_{PV}) \cdot cos(h) \cdot cos(\alpha - \alpha_{PV})\] where \(\beta_{PV}\) is the incline angle of the PV module and \(\alpha_{PV}\) is the azimuth of the PV module. For today’s implementation we are only interested in PV modules that are inclined towards the South, so \(\alpha_{PV} = 0\).

Again, we need to consider a special case: Whenever \(cos(\theta) < 0\) the sunlight does actually not shine onto the surface of our PV module. We can therefore set all these values to \(0\).

Finally, with all the information above, we can compute the solar irradiance \(G\) onto an inclined surface, such as a PV module, for any location on Earth at any time of year and day by \[G = \frac{G_0}{sin(h)} cos(\theta)\] where \(G_0\) is the solar irradiance onto a horizontal surface. We typically obtain \(G_0\) from measurement or model data sets. In our solar module we will parameterize \(G_0\) and use it as an upper-limit proxy for clear-sky solar irradiance. The parameterization is based on the solar constant and considerations around the location on Earth as well as the time of year and day.

Disclaimer

The above equations are based on simplifications and approximations. Use the information without warranty.

Exercises

#06-01: Our module solar
  • On ILIAS, you will find a file 06_unit/solar.py. This is a starting point to the module you will write for this exercise.
  • Closely look at the functions convert_utc2localsolar() and comp_hourangle() and try to understand how they handle time, as well as how they are implemented in general.
  • Create several functions in the module: comp_declination(), comp_elevangle(), comp_solarazimuth(), comp_cos_incidenceangle(), comp_irradiance_incline(). Use the functions that I already provided in the module as template. The previous section contains all the relevant math equations you will need for your module. If you are interested to deeper understand the theory behind these equations, you will find many resources on the internet.

With all the equations packed into our module, we can now answer and visualize some pretty cool questions. Start a new notebook and solve the remaining exercises there.

#06-02: Applying our module solar
  1. We want to look at the entire year 2023 in Dornbirn. Create a Pandas DataFrame indexed by the datetime of the year in hourly sampling.
  2. Use all the functions that we have in our solar module to compute new columns of the DataFrame: the hourangle, the declination, the solar elevation angle, the solar azimuth, and also the clear-sky irradiance. Use the latitude and longitude of Dornbirn as defined by the variables lat_DO and lon_DO in solar.
  3. When computing the DataFrame, I get a runtime warning that there were invalid values encountered in a function call to arccos. This means, we have to expect some missing values in our data set. Use the DataFrame methods .isna() and .sum() to check how many NaN’s our data set contains and which columns are affected.
#06-03: Idealized conditions in Dornbirn

Let’s look a bit deeper into the idealized clear-sky irradiance in Dornbirn over 2023.

  1. Create quick working plots like the following ones without spending time to style them etc. You just want to look at the data as conveniently and quickly as possible.

  1. Compute the maximum and median clear-sky irradiance for Dornbirn each day in 2023. Similarly to your working plots above, apply the Pandas .plot() method (here, .plot.area()) to create a plot that you then style a little bit with legend, title, ylabel. Make it look as closely as possible to that one:

Note that the circles representing monthly means are a bit of a tricky part, here are a few tips: * First resample to monthly sampling, compute the average, and then sample back to daily sampling (taking the sum of upsampled values). * The start or end of each month (depending on your sampling frequency 'M' or 'MS') will then have the desired values, all other days will contain zeros. Set all the zeros to NaN. * To display the circles at the mid of each month of the graph, add a time offset of 15 days to the index of your resampled monthly mean Pandas Series.

#06-04: Histograms

We stick with the same DataFrame, but want to look at the data in a different way.

  1. We start simple and create some very quick working plots. A histogram of the solar elevation angle and one of the solar azimuth.
  2. Now that you have your working plots, let’s modify them a bit. Create three panels next to each other that share the same y-axis. Try to emulate the following plot as closely as possible.

Working with angles would lend itself to plotting on a polar axis. There is nothing like a polar histogram readily available on matplotlib, but a quick Internet search highlights several solutions to modify the matplotlib barchart on a polar axis to your needs. An example with random data for your inspiration:

#06-05: Save DataFrame

We will continue to work with our DataFrame next week, so save it to a file solar_Dornbirn.csv.