Skip to content

Commit 9ceaf5b

Browse files
committed
Initial work
1 parent 9b98d9e commit 9ceaf5b

File tree

4 files changed

+133
-1
lines changed

4 files changed

+133
-1
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""
2+
Calculating power loss from partial module shading
3+
==================================================
4+
5+
Example of modeling cell-to-cell mismatch loss from partial module shading.
6+
"""
7+
8+
# %%
9+
# Even though the PV cell is the primary power generation unit, PV modeling is
10+
# often done at the module level for simplicity because module-level parameters
11+
# are much more available and it significantly reduces the computational scope
12+
# of the simulation. However, module-level simulations are too coarse to be
13+
# able to model effects like cell to cell mismatch or partial shading. This
14+
# example calculates cell-level IV curves and combines them to reconstruct
15+
# the module-level IV curve. It uses this approach to find the maximum power
16+
# under various shading and irradiance conditions.
17+
#
18+
# The primary functions used here are:
19+
#
20+
# - :py:meth:`pvlib.pvsystem.calcparams_desoto` to estimate the single
21+
# diode equation parameters at some specified operating conditions.
22+
# - :py:meth:`pvlib.singlediode.bishop88` to calculate the full cell IV curve,
23+
# including the reverse bias region.
24+
#
25+
# .. note::
26+
#
27+
# This example requires the reverse bias functionality added in pvlib 0.7.2
28+
#
29+
# .. warning::
30+
#
31+
# Modeling partial module shading is complicated and depends significantly
32+
# on the module's electrical topology. This example makes some simplifying
33+
# assumptions that are not generally applicable. For instance, it assumes
34+
# that shading only applies to beam irradiance (*i.e.* all cells receive
35+
# the same amount of diffuse irradiance) and cell temperature is uniform
36+
# and not affected by cell-level irradiance variation.
37+
38+
from pvlib import pvsystem, singlediode
39+
import pandas as pd
40+
import numpy as np
41+
from scipy.interpolate import interp1d
42+
import matplotlib.pyplot as plt
43+
44+
from scipy.constants import e as qe, k as kB
45+
46+
47+
# %%
48+
# Simulating a cell IV curve
49+
# --------------------------
50+
#
51+
# First, calculate IV curves for individual cells. The process is as follows:
52+
#

docs/sphinx/source/reference/effects_on_pv_system_output/shading.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ Shading
1212
shading.sky_diffuse_passias
1313
shading.projected_solar_zenith_angle
1414
shading.shaded_fraction1d
15-
15+
shading.martinez_shade_factor

pvlib/shading.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,3 +553,77 @@ def shaded_fraction1d(
553553
)
554554

555555
return np.clip(t_asterisk, 0, 1)
556+
557+
558+
def martinez_shade_factor(shaded_fraction, N_shaded_blocks, N_total_blocks):
559+
r"""
560+
A shading correction factor for the power yield of non-monolithic Silicon
561+
modules and arrays with an arbitrary number of bypass diodes.
562+
shaded_fraction : numeric
563+
Surface shaded fraction. Unitless.
564+
shaded_blocks : numeric
565+
Number of blocks affected by the shadow. Unitless integer.
566+
total_blocks : numeric
567+
Number of total blocks. Unitless integer.
568+
569+
Returns
570+
-------
571+
shading_correction_factor : numeric
572+
Multiply unshaded power by this factor.
573+
574+
Notes
575+
-----
576+
The implemented equation is (6) from [1]_:
577+
578+
.. math::
579+
580+
(1 - F_{ES}) = (1 - F_{GS}) (1 - \frac{N_{SB}}{N_{TB} + 1})
581+
582+
Where :math:`(1 - F_{ES})` is the correction factor to be multiplied by
583+
the unshaded irradiance, :math:`F_{GS}` is the shaded fraction,
584+
:math:`N_{SB}` is the number of shaded blocks and :math:`N_{TB}` is the
585+
number of total blocks.
586+
587+
Blocks terminology
588+
^^^^^^^^^^^^^^^^^^
589+
[1]_ defines a *block* as a group of solar cells protected by a bypass
590+
diode. Also, a *block* is shaded when at least one of its cells is shaded.
591+
592+
How many blocks and their layout depend on the module(s) used. Many
593+
manufacturers don't specify this information explicitly. However, we can
594+
infer these values from:
595+
- the number of bypass diodes
596+
- where and how many junction boxes are present on the back of the module
597+
- whether or not the module is comprised of *half-cut cells*
598+
The latter two are heavily correlated.
599+
600+
Examples
601+
--------
602+
Minimal example. For a complete example, see
603+
:ref:`this example <sphx_glr_gallery_plot_martinez_shade_loss.py>`
604+
>>> import numpy as np
605+
>>> from pvlib import shading
606+
>>> total_blocks = 3 # blocks along the vertical of the module
607+
>>> Pwr_out_unshaded = 100 # kW
608+
>>> shaded_fraction = shading.shaded_fraction1d(
609+
TODO copy from linear loss PR
610+
)
611+
>>> shaded_blocks = np.ceil(total_blocks*shaded_fraction)
612+
>>> loss_correction = shading.martinez_shade_factor()
613+
>>> Pwr_out_shaded = Pwr_out_unshaded * loss_correction
614+
615+
See Also
616+
--------
617+
pvlib.shading.linear_shade_loss for monolithic thin film modules
618+
619+
References
620+
----------
621+
.. [1] F. Martínez-Moreno, J. Muñoz, and E. Lorenzo, 'Experimental model
622+
to estimate shading losses on PV arrays', Solar Energy Materials and
623+
Solar Cells, vol. 94, no. 12, pp. 2298-2303, Dec. 2010,
624+
:doi:`10.1016/j.solmat.2010.07.029`.
625+
""" # Contributed by Echedey Luis, 2024
626+
return ( # Eq. (6) of [1]
627+
(1 - shaded_fraction)
628+
* (1 - N_shaded_blocks / (1 + N_total_blocks))
629+
)

pvlib/tests/test_shading.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,9 @@ def test_shaded_fraction1d(sf1d_premises_and_expected):
307307
sf_vec = shading.shaded_fraction1d(**premises)
308308
assert_allclose(sf_vec, expected_sf_array, atol=1e-6)
309309
assert isinstance(sf_vec, pd.Series)
310+
311+
312+
def test_martinez_shade_factor():
313+
"""Tests pvlib.shading.martinez_shade_factor"""
314+
# TODO
315+
pass

0 commit comments

Comments
 (0)