Skip to content

Commit 74c9eeb

Browse files
committed
More improvements
1 parent d6ed488 commit 74c9eeb

File tree

2 files changed

+109
-11
lines changed

2 files changed

+109
-11
lines changed

docs/examples/shading/plot_martinez_shade_loss.py

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,129 @@
77
"""
88

99
# %%
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]_.
1111
# The model is implemented in :py:func:`pvlib.shading.martinez_shade_loss`.
1212
# This model corrects the beam and circumsolar incident irradiance
1313
# based on the number of shaded *blocks*. A *block* is defined as a
1414
# group of cells that are protected by a bypass diode.
1515
# 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.
1717
#
1818
# The following key functions are used in this example:
1919
# 1. :py:func:`pvlib.shading.martinez_shade_loss` to calculate the adjustment
20+
# factor for the direct irradiance component.
2021
# 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.
2324
#
2425
# .. 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.
2549

26-
from pvlib import shading
50+
import pvlib
2751
import pandas as pd
2852
import numpy as np
29-
from scipy.interpolate import interp1d
3053
import matplotlib.pyplot as plt
3154

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"]
3378

3479
# %%
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.
3885

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+
)

pvlib/shading.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@ def martinez_shade_factor(shaded_fraction, N_shaded_blocks, N_total_blocks):
552552
Surface shaded fraction. Unitless.
553553
shaded_blocks : numeric
554554
Number of blocks affected by the shadow. Unitless integer.
555+
If a floating point number is provided, it will be rounded up.
555556
total_blocks : numeric
556557
Number of total blocks. Unitless integer.
557558
@@ -627,5 +628,5 @@ def martinez_shade_factor(shaded_fraction, N_shaded_blocks, N_total_blocks):
627628
""" # Contributed by Echedey Luis, 2024
628629
return ( # Eq. (6) of [1]
629630
(1 - shaded_fraction)
630-
* (1 - N_shaded_blocks / (1 + N_total_blocks))
631+
* (1 - np.ceil(N_shaded_blocks) / (1 + N_total_blocks))
631632
)

0 commit comments

Comments
 (0)