|
7 | 7 | """
|
8 | 8 |
|
9 | 9 | # %%
|
10 |
| -# The example is based on the work of Martinez et al. [1]_. |
| 10 | +# This example illustrates how to use the work of Martinez et al. [1]_. |
11 | 11 | # The model is implemented in :py:func:`pvlib.shading.martinez_shade_loss`.
|
12 | 12 | # This model corrects the beam and circumsolar incident irradiance
|
13 | 13 | # based on the number of shaded *blocks*. A *block* is defined as a
|
14 | 14 | # group of cells that are protected by a bypass diode.
|
15 | 15 | # More information on the *blocks* can be found in the original paper [1]_ and
|
16 |
| -# in the function documentation. |
| 16 | +# in :py:func:`pvlib.shading.martinez_shade_loss` documentation. |
17 | 17 | #
|
18 | 18 | # The following key functions are used in this example:
|
19 | 19 | # 1. :py:func:`pvlib.shading.martinez_shade_loss` to calculate the adjustment
|
| 20 | +# factor for the direct irradiance component. |
20 | 21 | # 2. :py:func:`pvlib.shading.shading_factor1d` to calculate the fraction of
|
21 |
| -# shaded surface and the number of shaded *blocks*, due to row-to-row |
22 |
| -# shading |
| 22 | +# shaded surface and consequently the number of shaded *blocks* due to |
| 23 | +# row-to-row shading. |
23 | 24 | #
|
24 | 25 | # .. sectionauthor:: Echedey Luis <echelual (at) gmail.com>
|
| 26 | +# |
| 27 | +# References |
| 28 | +# ---------- |
| 29 | +# .. [1] F. Martínez-Moreno, J. Muñoz, and E. Lorenzo, 'Experimental model |
| 30 | +# to estimate shading losses on PV arrays', Solar Energy Materials and |
| 31 | +# Solar Cells, vol. 94, no. 12, pp. 2298-2303, Dec. 2010, |
| 32 | +# :doi:`10.1016/j.solmat.2010.07.029`. |
| 33 | +# |
| 34 | +# Problem description |
| 35 | +# ------------------- |
| 36 | +# Let's consider a PV system with the following characteristics: |
| 37 | +# - Two north-south single-axis tracker with 6 modules each one. |
| 38 | +# - The rows have the same true-tracking tilt angles. |
| 39 | +# - Terrain slope is 7 degrees downward to the east. |
| 40 | +# - Row's axis are horizontal. |
| 41 | +# - The modules are comprised of silicon cells. We will compare these cases: |
| 42 | +# - modules with one bypass diode |
| 43 | +# - modules with three bypass diodes |
| 44 | +# - half-cut cell modules with three bypass diodes on portrait and landscape |
| 45 | +# |
| 46 | +# Setting up the system |
| 47 | +# ---------------------- |
| 48 | +# Let's start by defining the location and the time range for the analysis. |
25 | 49 |
|
26 |
| -from pvlib import shading |
| 50 | +import pvlib |
27 | 51 | import pandas as pd
|
28 | 52 | import numpy as np
|
29 |
| -from scipy.interpolate import interp1d |
30 | 53 | import matplotlib.pyplot as plt
|
31 | 54 |
|
32 |
| -# TODO: REBASE FROM SHADING_FACTOR1D |
| 55 | +from pathlib import Path |
| 56 | + |
| 57 | +pitch = 4 # meters |
| 58 | +width = 1.5 # meters |
| 59 | +gcr = width / pitch |
| 60 | +N_modules_per_row = 6 |
| 61 | +axis_azimuth = 180 # N-S axis |
| 62 | +axis_tilt = 0 # flat because the axis is perpendicular to the slope |
| 63 | +cross_axis_tilt = -7 # 7 degrees downward to the east |
| 64 | + |
| 65 | +# Get TMY data & create location |
| 66 | +datapath = Path(pvlib.__path__[0], "data", "tmy_45.000_8.000_2005_2016.csv") |
| 67 | +pvgis_data, _, metadata, _ = pvlib.iotools.read_pvgis_tmy( |
| 68 | + datapath, map_variables=True |
| 69 | +) |
| 70 | +locus = pvlib.location.Location( |
| 71 | + metadata["latitude"], metadata["longitude"], altitude=metadata["elevation"] |
| 72 | +) |
| 73 | + |
| 74 | +# Coerce a year: function above returns typical months of different years |
| 75 | +pvgis_data.index = [ts.replace(year=2024) for ts in pvgis_data.index] |
| 76 | +# Select day to show |
| 77 | +weather_data = pvgis_data["2024-07-11"] |
33 | 78 |
|
34 | 79 | # %%
|
35 |
| -# yolo |
36 |
| -# -------------------------- |
37 |
| -# |
| 80 | +# True-tracking algorithm |
| 81 | +# ----------------------- |
| 82 | +# Since this model is about row-to-row shading, we will use the true-tracking |
| 83 | +# algorithm to calculate the trackers rotation. Back-tracking avoids shading |
| 84 | +# between rows, which is not what we want to analyze here. |
38 | 85 |
|
| 86 | +# Calculate solar position to get single-axis tracker rotation and irradiance |
| 87 | +solar_pos = locus.get_solarposition(weather_data.index) |
| 88 | +apparent_zenith, apparent_azimuth = ( |
| 89 | + solar_pos["apparent_zenith"], |
| 90 | + solar_pos["azimuth"], |
| 91 | +) # unpack references to data for better readability |
| 92 | + |
| 93 | +tracking_result = pvlib.tracking.singleaxis( |
| 94 | + apparent_zenith=apparent_zenith, |
| 95 | + apparent_azimuth=apparent_azimuth, |
| 96 | + axis_tilt=axis_tilt, |
| 97 | + axis_azimuth=axis_azimuth, |
| 98 | + max_angle=(-90 + cross_axis_tilt, 90 + cross_axis_tilt), # (min, max) |
| 99 | + backtrack=False, |
| 100 | + gcr=gcr, |
| 101 | + cross_axis_tilt=cross_axis_tilt, |
| 102 | +) |
| 103 | + |
| 104 | +tracker_theta, aoi, surface_tilt, surface_azimuth = ( |
| 105 | + tracking_result["tracker_theta"], |
| 106 | + tracking_result["aoi"], |
| 107 | + tracking_result["surface_tilt"], |
| 108 | + tracking_result["surface_azimuth"], |
| 109 | +) # unpack references into explicit variables for better readability |
| 110 | + |
| 111 | +extra_rad = pvlib.irradiance.get_extra_radiation(weather_data.index) |
| 112 | + |
| 113 | +poa_sky_diffuse = pvlib.irradiance.haydavies( |
| 114 | + surface_tilt, |
| 115 | + surface_azimuth, |
| 116 | + weather_data["dhi"], |
| 117 | + weather_data["dni"], |
| 118 | + extra_rad, |
| 119 | + apparent_zenith, |
| 120 | + apparent_azimuth, |
| 121 | +) |
| 122 | + |
| 123 | +poa_ground_diffuse = pvlib.irradiance.get_ground_diffuse( |
| 124 | + surface_tilt, weather_data["ghi"], surface_type="grass" |
| 125 | +) |
| 126 | + |
| 127 | +# %% |
| 128 | +# Shaded fraction calculation |
| 129 | +# --------------------------- |
| 130 | +# The next step is to calculate the fraction of shaded surface. This is done |
| 131 | +# using the :py:func:`pvlib.shading.shading_factor1d` function. Using this |
| 132 | +# function is straightforward with the amount of information we already have. |
| 133 | +shaded_fraction = pvlib.shading.shading_factor1d( |
| 134 | + surface_tilt, surface_azimuth, apparent_zenith, apparent_azimuth |
| 135 | +) |
0 commit comments