Back to Article
Assignment #08
Download Notebook

Assignment #08

In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from importlib import reload
import solar
reload(solar)
<module 'solar' from '/home/flo/documents/fhv/LV_programming_NES/Programmiertechniken/08_files/solar.py'>
In [2]:
sdo = pd.read_csv('solar_Dornbirn.csv', parse_dates=True, index_col='datetime')
sdo
tau declination h alpha iswr_clearsky
datetime
2023-01-01 00:00:00 -180.0 -22.930544 -65.518144 NaN 0.0
2023-01-01 01:00:00 -165.0 -22.930544 -62.729858 211.348308 0.0
2023-01-01 02:00:00 -150.0 -22.930544 -55.750441 234.906273 0.0
2023-01-01 03:00:00 -135.0 -22.930544 -46.681349 251.665818 0.0
2023-01-01 04:00:00 -120.0 -22.930544 -36.760543 264.601524 0.0
... ... ... ... ... ...
2023-12-30 20:00:00 120.0 -23.085911 -36.866391 95.256414 0.0
2023-12-30 21:00:00 135.0 -23.085911 -46.792577 108.175901 0.0
2023-12-30 22:00:00 150.0 -23.085911 -55.874482 124.927227 0.0
2023-12-30 23:00:00 165.0 -23.085911 -62.873366 148.521437 0.0
2023-12-31 00:00:00 -180.0 -23.011637 -65.599237 NaN 0.0

8737 rows × 5 columns

In [3]:
def comp_energy_produced(iswr0, beta, pvazimuth, elevangle, azimuth, datetime = None, efficiency=0.2, area=1):
    """
    Calculate the energy produced by a PV module based on solar irradiance data.

    Parameters
    ----------
    iswr0 (pandas.Series): Solar irradiance data onto horizontal surface.
    beta (float): Incline angle of the PV module (in degrees).
    pvazimuth (float): Azimuth angle of the PV module (in degrees, 0 in the south).
    elevangle (array-like): Elevation angle of the sun (in degrees).
    azimuth (array-like): Azimuth angle of the sun (in degrees, 0 in the south).
    datetime (pandas.Series or None, optional): Timestamps associated with the irradiance data. If None, 
        the function assumes regular time intervals based on the index of 'iswr0'.
    efficiency (float, optional): Efficiency of the photovoltaic system (default is 0.2).
    area (float, optional): Area of the PV module (default is 1).

    Returns
    -------
    float: Total energy produced by the photovoltaic system (in Wh).

    If 'datetime' is not provided, the function assumes regular time intervals based on the index of 'iswr0'.
    The function raises a ValueError if the time intervals are irregular.
    """

    if datetime is None:
        datetime = iswr0.index.to_series()

    # Retrieve unique time sampling dt in (hours)
    delta = datetime.diff()
    dt = delta.dt.total_seconds()/3600
    dt = dt[dt.notna()].unique()
    if (len(dt) > 1):
        raise ValueError("Irregular time sampling is not allowed")
    
    # Calculate iswr onto inclined PV module
    iswr_beta = solar.comp_irradiance_incline(iswr0, 
                                              solar.comp_cos_incidenceangle(elevangle, azimuth, beta, pvazimuth),
                                              elevangle)
    # Calculate generated power and energy
    power = iswr_beta * area * efficiency
    energy = power.sum() * dt

    return energy[0]

Finally, you can perform the grid search:

In [4]:
alpha_pv = np.arange(-180, 180, 5)
beta_pv = np.arange(0, 95, 5)

APV, BPV = np.meshgrid(alpha_pv, beta_pv)
Z = np.full(APV.shape, np.nan)
In [14]:
for i, _ in enumerate(alpha_pv):
    for j, _ in enumerate(beta_pv):
        # print(i, j, APV[j, i], BPV[j, i])
        Z[j, i] = comp_energy_produced(sdo['iswr_clearsky'], BPV[j, i], APV[j, i], sdo['h'], sdo['alpha'])

i_max = np.argmax(Z[~np.isnan(Z)])
Z_max = np.max(Z[~np.isnan(Z)])
Z = Z/Z_max
In [19]:
print(f"Optimal PV position: azimuth {APV[np.unravel_index(i_max, APV.shape)]}, incline {BPV[np.unravel_index(i_max, APV.shape)]}")
Optimal PV position: azimuth -5, incline 45
In [26]:
f, ax = plt.subplots(figsize=(12, 5))
cf = ax.contourf(alpha_pv, beta_pv, Z, levels=30, cmap='Reds', extend='both')
cbar = f.colorbar(cf)
ax.scatter(APV[np.unravel_index(i_max, APV.shape)], BPV[np.unravel_index(i_max, APV.shape)], color='black')
cbar.set_label("Percentage of maximum (%)")
ax.set_ylabel(r"PV incline ($^\circ$)")
ax.set_xlabel(r"PV azimuth ($^\circ$): W <----> E")
ax.set_title("Annual energy production under idealized conditions in Dornbirn, 2023")
# plt.savefig("contourplot.png")
Text(0.5, 1.0, 'Annual energy production under idealized conditions in Dornbirn, 2023')